do semaphores satisfies bounded waiting - semaphore

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.

Related

Why a guard exists in this implementation of a lock?

Here in this video at 26:00, there is an implementation of a lock that tries to avoids busy waiting as much as possible by using a wait queue, the code looks like this (pseudo code):
int guard = 0;
int value = FREE;
Acquire()
{
while (test_and_set(guard));
if (value == BUSY) {
release_guard_and_wait();
} else {
value = BUSY;
guard = 0;
}
}
Release()
{
while (test_and_set(guard));
if (!wait_queue.empty())
wake_one();
else
value = FREE;
guard = 0;
}
test_and_set is an atomic operation that returns the old value of guard and sets it to 1.
release_guard_and_wait has to be atomic as well to avoid potential problems:
If the thread waits then releases the guard when it wakes up, no thread will be able to acquire it.
If the thread releases the guard then waits, this scenario might happen:
thread 1 (in Acquire) -> guard = 0;
thread 2 (in Release) -> test_and_set(guard);
thread 2 (in Release) -> wake_one();
thread 1 (in Acquire) -> wait();
thread 2 (in Release) -> guard = 0;
wake_one wakes one thread (takes it from the wait queue and puts it in the ready queue).
My question is, why using guard? isn't this redundant?
The code without guard may look like this:
int value = 0;
Acquire()
{
while (test_and_set(value))
wait();
}
Release()
{
value = 0;
wake_one();
}
Will these two implementations behave differently under some conditions? Is there any advantage in using the guard?
There are two big problems with your code.
First, your code has a race condition. Consider:
Thread 1 holds the lock, it calls Release.
Thread 2 wants the lock, it calls Acquire.
Thread 1 sets value to zero.
Thread 2 passes the test_and_set.
Thread 1 calls wake_one, it doesn't do anything.
Thread 2 calls wait, it is waiting for a wakeup that already happened.
Oops, deadlock. This is why you need an atomic release_guard_and_wait function.
Second problem:
If two threads call Acquire at the same time, your code will only cause one of them to wait. The other one will do horrible things, for example it will:
Keep a core busy, preventing other cores from reaching their peak speeds on many CPUs with adaptive clock speeds.
Waste power.
Starve another thread running in the same core on CPUs with hyperthreading and similar technologies.
When the spinning thread finally does pass the test_and_set loop, it will take a massive mispredicted branch penalty. So if several threads are waiting, each one will stall just as it gets the lock. Yuck.
On some CPUs, a test_and_set loop will cause inter-core traffic even if the comparison fails. So you may saturate inter-core buses, slowing other innocent threads (and the one holding the lock) to a crawl.
And so on.
I hate to see the test and set loop in the original code (that's only appropriate in toy code, even for very short times) but at least it won't spin for the whole time another thread holds the lock as yours will.
"there is an implementation of a lock that avoids busy waiting by using a wait channel" -- I could still see a busy waiting, in the form of this while (test_and_set(guard));). But the essence of the code is making that busy wait for a short period. All your code does is this:
Declare a lock-queue where a process can register itself for a lock.
Add the process to that lock-queue, which is interested in acquiring the lock.
Release one process from the lock-queue, when an already holding process releases the lock.
Acquire()
while (test_and_set(guard)); -- Get the gaurd for editing the lock-queue.
if (value == BUSY) {release_guard_and_wait();} -- If the lock is already acquired, add yourself to the lock-queue, and release the guard on lock-queue so that other processes may add themselves to the lock-queue. And wait till you are given a call to wake up.
else { value = BUSY; guard = 0;} -- If no process acquired the lock, then acquire by yourself and release the guard on the lock-queue.
Release()
while (test_and_set(guard)); -- Get the gaurd for editing the lock-queue.
if (!wait_queue.empty()) wake_one(); -- If the lock queue is not empty then wake one process.
else value = FREE; -- If no process is waiting for the lock in the lock-queue, just release the lock.
guard = 0; -- Of course at the end, release the guard on the lock-queue, so other processes can edit the queue.
Now coming to your modified code, you can immediately find that two processes running acquire() and release() may edit the queue at the same instant. Moreover, multiple processes trying to acquire the lock at the same time, may also corrupt the lock-queue and leave it in a broken state.

Starvation Free Mutex In Little Book of Semaphores

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.

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.

Which thread gets scheduled after first thread has exited?

void main()
{
.....
pthread_mutex_init(&lock)
pthread_create(fun,...)
pthread_create(fun,...)
pthread_create(fun,...)
}
void fun()
{
pthread_mutex_lock(&lock)
...........
pthread_mutex_unlock(&lock)
}
In the code above, I created 3 threads calling same function fun. I can tell you that execution of fun takes long than creating the threads. So there are 3 threads initially. But 1st thread is already executing after taking lock. Now 2nd and third thread are waiting. My question is once the lock is released which thread will be scheduled. Is it 2nd thread and then third or depends on the scheduler. Does scheduler maintain any kind of queue for the waiting threads and schedules it in FIFO manner?
No, it does not work like a FIFO. One thread at random will be woken up.

Thread deletion design

I have multi thread program. I have a design of my application as follows:
Suppose one is main thread, and other are slave threads. Main thread keep track of all slave thread ID's. During one of the scenario of application (one of the scenario is graceful shutdown of application), i want to delete slave threads from main thread.
Here slave threads may be executing i.e., either in sleep mode or doing some action which i cannot stop the action. So i want to delete the threads from main thread with thread IDs i stored internally.
Additional info:
While deleting i should not wait for thread current action to complete as it may take long time as i am reading from data base and taking some action in thread, in case of gracefull shut down i should not wait for action to complete as it may take time.
If i force delete a thread how can there will be a resource leaks?
Is above design is ok or there is any flow or any ways we can improve the design.
Thanks!
It's not okay. It's a bad practice to forcefully kill a thread from another thread because you'll very likely to have resource leaks. The best way is to use an event or signal to signal the client process to stop and wait until they exit gracefully.
The overall flow of the program would look like this:
Parent thread creates an event (say hEventParent). it then creates child threads and passes hEventParent as a parameter. The Parent thread keeps the hThread of the child thread(s).
Child threads do work but periodically waits for hEventParent.
When the program needs to exit, the parent thread sets hEventParent. It then waits for hThread (WaitForMultipleObjects also accepts hThread)
Child thread is notified then execute clean up routine and exits.
When all the threads exit, the parent can then exit.
The most common approach consists in the main thread sending a termination signal to all the threads, then waiting for the threads to end.
Typically the worker threads will have a loop, inside of which the work is done. You can add a boolean variable that indicates if the thread needs to end. For example:
terminate = false;
while (!terminate) {
// work here
}
If you want your worker threads to go to sleep when they have no work, then it gets a bit more complicated. In this case you could make the threads wait on semaphores. Each semaphore will be signaled when there is work to do, and that will awaken the thread. You will also signal the semaphore when the request to terminate is issued. Example worker thread:
terminate = false;
while (!terminate) {
// work here
wait(semaphore); // go to sleep
}
When the main thread wants to exit it will set terminate to true for all the threads and then signal the thread semaphores to awaken the threads and give them a chance to see the termination request. After that it will join all the threads, and only after all the threads are finished it will exit.
Note that the terminate boolean may need to be declared as volatile if you are using C/C++, to indicate to the compiler that it may be changed from another thread.

Resources