Starvation Free Mutex In Little Book of Semaphores - multithreading

Background:
The Little Book of Semaphores by Allen B. Downey talks about assumptions needed to prevent thread starvation.
He states that the scheduler needs to guarantee the following:
Property 2: if a thread is ready to run, then the time it waits until it runs is bounded.
And a weak semaphore guarantees:
Property 3: if there are threads waiting on a semaphore when a thread executes signal, then one of the waiting threads has to be woken.
However, he states that even with these properties, the following code when run for 3 or more threads (Thread A,B,C) can cause starvation:
while True:
mutex.wait()
# critical section
mutex.signal()
The argument is that if A executes first, then wakes up B, A could wait on the mutex again before B releases it. At this point, the A could be woken up again reacquire the mutex and repeat this cycle with B. C would be starved.
Question:
Wouldn't Property 2 guarantee that C would have to be woken up by the scheduler in some finite amount of time? If so, then Thread C couldn't be starved. Even if weak semaphore does not guarantee that Thread C will be woken up, shouldn't the scheduler run it?

I thought about it a little bit more and realized that Property 2 is guarantees that Threads in a RUNNABLE state will be scheduled in a finite amount of time.
The argument in the book states that Thread C would never get to a RUNNABLE state so Property 2 and 3 do not guarantee no starvation.

Related

Can two wait operations executed by two separate threads on different semaphores be interleaved during execution?

I'm motivated with this citation from "Concepts in Programming Languages" by John C. Mitchell:
"Atomicity prevents individual statements of one wait procedure from being
interleaved with individual statements of another wait on the same semaphore."
Wait and signal operations need to be atomic which is often enforced by some "lower" level mechanism of acquiring lock - disabling interrupts, disabling preemption, test and set ... But, conceptually, how these locks can be in some way "private" for each semaphore instance?
In other words, is it allowed for example that one thread acquires lock at the beginning and later be preempted in the middle of executing wait operation on one semaphore, and after that another thread acquires lock at the beginning of wait operation on some other semaphore and enters in the body of its wait operation, so that two thread are in the wait operations on different semaphores at the same time? Or, shortly, whether the wait operations on two different semaphores mutually exclusive?
My point is, if thread acquires lock in wait operation on one semaphore s1, is it allowed for another thread to acquire lock at the same time in wait operation on another semaphore s2? I'm emphasizing that these are two different semaphore instances, not the same one.
For example:
class Semaphore {
...
public:
void wait();
...
}
void Semaphore::wait(){
lock();
//POINT OF CONTINUATION FOR THREAD 2!//
if(--val<0){
//POINT OF PREEMPTION FOR THREAD 1!//
block();
}
unlock();
}
Semaphore s1;
Semaphore s2:
...
So...
Is it allowed at some point of execution that one thread be preempted while executing wait operation on semaphore s1 at //POINT OF PREEMPTION FOR THREAD 1!// , and control transfers to another thread which executes wait operation of semaphore s2 at //POINT OF CONTINUATION FOR THREAD 2!//...
...or...
Is it allowed for instructions of wait operation from one semaphore to be interleaved with instruction of wait operation from another semaphore?
..or...
Is it allowed for more than one threads to be in wait operations on different semaphores at the same time?
Sorry for my wordiness but I really struggle to clarify my question. Thanks in advance.
Yes, it's allowed. One of the reasons you would use two different locks, rather than using the same lock for everything, is to avoid unnecessary dependencies like this.
Is it allowed for instructions of wait operation from one semaphore to be interleaved with instruction of wait operation from another semaphore?
Absolutely.
Is it allowed for more than one threads to be in wait operations on different semaphores at the same time?
Absolutely.
Prohibiting any of these things would hurt performance significantly for no benefit. Contention is the enemy of multi-threaded performance.

How can any thread signal for release of a binary semaphore

I am new to multithreading paradigm. While learning concurrency, every source I found says:
"The difference between mutex and binary semaphore is the ownership
i.e. a mutex can be signaled for release by only the thread who
created it while a semaphore can be signaled any thread"
Considering a scenario where thread A has acquired a binary semaphore lock on resource x and processing it. If any thread can call a release signal for lock on x, doesn't this open a possibility of any thread calling a release on the lock amidst the time when thread A was using x.
Isn't there a scope of inconsistency in this or am I missing something?
Of course, if threads are arbitrarily acquiring or releasing a semaphore, the result would be disastrous and the fact, that implementations do not prevent this, does not imply that this is a useful scenario.
However, there might be real use cases if the involved threads use another mechanism to coordinate themselves while using the semaphore to hold these threads off which do not participate in these coordination.
Imagine you expand a use case where one thread acquires the semaphore for performing a task to parallel execution of said task. After acquiring the semaphore, several worker threads are spawned, each of them working on a different part of the data, thus naturally working non-interfering. Then the last worker thread releases the semaphore which elides the need for another communication between the initiating thread and the worker threads. Of course, this requires the worker thread to detect whether it is the last one, but a simple atomic integer holding the number of active workers would be sufficient.

What is the Mutex acquire and release order?

I know the functionality of Mutex. But now I am confused about its timing. I specially mean in the Linux kernel code.
For example, we have 3 threads (let's say they are on the same processor and are all normal tasks with the same priorities). Thread 1 ,2 and 3 try to acquire the Mutex and only Thread 1 gets it. Thread 2 and 3 are blocked and go to sleep. Then Thread 1 has done his job and unlock the Mutex.
So here is my question: At this very moment, what will happen? Will Thread 1 continue to execute because its scheduled time slice is not used up? Or will Thread 2 acquire the lock immediately and start to execute because it is the second thread who wants to acquire the lock? Or will Thread 3 acquire the lock immediately and start to execute because it is assumed to run next from the task scheduler(Let's assume this)? What will happen?
Once Thread 1 releases the lock, what happens next is non-deterministic. Any of the scenarios you outlined above are possible.
If your application requires a very specific order among threads, then you might want to try having the threads communicate more explicitly among themselves. In C, you can do this with a pipe().
Generally though, the performance is best if you embrace the chaos and let the scheduler choose.
Once Thread 1 has done his job, he gives the MUTEX back to others, and goes to sleep.

do semaphores satisfies bounded waiting

Does semaphore satisfies bounded waiting or they are just for providing mutual exclusion??
Answer
It may break bounded waiting condition theoretically as you'll see below. Practically, it depends heavily on which scheduling algorithm is used.
The classic implementation of wait() and signal() primitive is as:
//primitive
wait(semaphore* S)
{
S->value--;
if (S->value < 0)
{
add this process to S->list;
block();
}
}
//primitive
signal(semaphore* S)
{
S->value++;
if (S->value <= 0)
{
remove a process P from S->list;
wakeup(P);
}
}
When a process calls the wait() and fails the "if" test, it will put itself into a waiting list. If more than one processe are blocked on the same semaphore, they're all put into this list(or they are somehow linked together as you can imagine). When another process leaves critical section and calls signal(), one process in the waiting list will be chosen to wake up, ready to compete for CPU again. However, it's the scheduler who decides which process to pick from the waiting list. If the scheduling is implemented in a LIFO(last in first out) manner for instance, it's possible that some process are starved.
Example
T1: thread 1 calls wait(), enters critical section
T2: thread 2 calls wait(), blocked in waiting list
T3: thread 3 calls wait(), blocked in waiting list
T4: thread 1 leaves critical section, calls signal()
T5: scheduler wakes up thread 3
T6: thread 3 enters critical section
T7: thread 4 calls wait(), blocked in waiting list
T8: thread 3 leaves critical section, calls signal()
T9: scheduler wakes up thread 4
..
As you can see, although you implements/uses the semaphore correctly, thread 2 has a unbounded waiting time, even possibly starvation, caused by continuous entering of new processes.

When does this happen? Thread suspended while in critical section

I'm just wondering, if a thread is in a critical section, can it be preempted?
Thread A: Enter CR
Thread A: Get suspended
Thread B: Wants to enter CR but can't, because Thread A has the lock
If Thread A preempted, and so the mutex lock is stuck with Thread A, what can be done about this?
Suppose thread A is preempted by higher priority thread C. Now suppose thread B is in fact higher priority than C. If B becomes runnable, you have a classic case of priority inversion; Thread B (high priority) is stuck waiting for a resource held by Thread A (low priority). One cure for this is called priority inheritance.
With priority inheritance, when B blocks for the resource held by A (the critical section), thread A temporarily 'inherits' the priority of thread B. This allows A to preempt that bothersome middle-priority thread C, and when A is done with the resource, A goes back to its original priority. This gets A out of B's way, so to speak, eliminating the dead-lock.
Of course it can be preempted. Otherwise how the other threads could try to enter that critical section, if the only thread that is allowed to run within the process is the thread that owns the critical section?
Thread B in your example will wait until thread A is rescheduled and is finished with the crtical section. No surprise here. And if thread A, while in a critical section, also waits for a mutex owned by thead B, then it's a deadlock which you must resolve by revising your logic.

Resources