Priority Inversion: When a lower priority process is being waited on by a higher priority process to finish in its critical section it inherits the priority of the higher priority process so it cannot be preempted by a process > than the lower priority but < than the higher priority
This solution to priority inversion is known as priority inheritance
Newer languages can use memory transactions (like database transactions) that consist of atomic operations
Since functional languages have immutable data, they are safe from race conditions by default
Threads first request resources, then release them after they are used
e.g. io devices, cpu, open() and close() for files, etc.
A system table records whether each resource is free or allocated
Resource-allocation graph -> a system graph of threads as vertices with edges pointing to resources
A cyclic graph indicates a deadlock may exist
Deadlock exists if the requested resource type only has one instance (otherwise, another thread not in the cycle could release that resource and free up a thread)
Can occur when one process/thread grabs a value from memory, updates it, and before storing it back in a register, another processor grabs the outdated value from the register to use
2 or more processes are waiting indefinitely for an event that can only be caused by one of the waiting processes
e.g. a signal() to release a resource
Windows/Linux leave deadlock protection up to kernel developers
Databases detect and recover from deadlocks
To prevent deadlock by preventing circular wait, you can assign each resource a numeric ID and only allow requests in an increasing order of ID. This way thread one won’t request resource 1 then resource 2, while thread 2 requests resource 2 then resource 1
Deadlock avoidance algorithms
Resource requests from threads are only granted if granting the resource will keep the system in a safe state (guaranteed to prevent deadlock)
Since deadlock occurs so infrequently, sometimes it is just ignored. Deadlock avoidance algorithms can cause low throughput
Database transactions use locks and thus require deadlock detection algorithms
Periodically search for cycles in the wait-for graph. If a cycle is detected, choose a victim transaction to abort, freeing up the resources. Once the remaining transactions complete, re-issue this transaction