Understanding an exam answer on Semaphores - semaphore

This question came up in a practice exam. I do not really understand how they got to the answers that they said are correct.
I was hoping for some help understanding the question and how to answer it?
Thank you!

I think it all comes to this:
wait (P): If the value of semaphore variable is not negative, decrements it by 1. If the semaphore variable is now negative, the process executing wait is blocked (i.e., added to the semaphore's queue) until the value is greater or equal to 1. Otherwise, the process continues execution, having used a unit of the resource.
Source and More information
For the correct answers:
1) Since the semaphore is initially equal 0, thread 3 will block on P(S) waiting for another thread to do V(S). This will only happen on thread 1, and after A is completed. So no matter how long statement A takes to execute, thread 3 will wait until the instruction V(S) is executed. So A will always be executed before F.
2) The same concept applies with B and G. Before G you have to execute P(T) and this will wait for an instruction V(T). This only happens after B has been executed.
3) Since A is executed before F as demonstrated in (1), and F is always executed before G, A is always executed before G.
As for the incorrect answers:
a) A is executed before E? Maybe, but not always. Because thread 1 and thread 2 have to wait for a semaphore, thread 2 could execute B, V(T) and E faster than A, so in this case the sentence (a) is false.
b) B is executed before F? Maybe, but not always. Why? To execute F, thread 3 only depends on thread 1 (the semaphore S) so C and A can execute very fast and then go to F while B can be still executing because it is very slow.
d) C is executed before D? Maybe, but not always. Again, C might take a long time to execute and thread 1, since it has not to wait for any semaphore, could execute all its instructions very fast, before C is completed.

Related

Difference between mutex/spinlock/semaphore in this use case?

I'm not sure if my answers to the following exercise is correct:
Suppose the program is run with two threads. Further suppose that the
following sequence of events occurs:
Time Thread 0 Thread 1
0 pthread_mutex_lock(&mut0) pthread_mutex_lock(&mut1)
1 pthread_mutex_lock(&mut1) pthread_mutex_lock(&mut0)
b. Would this be a problem if the program used busy-waiting (with two flag
variables) instead of mutexes?
c. Would this be a problem if the program used semaphores instead of mutexes?
Are the outcomes for this not the exact same in that they'd result in a deadlock?
For b) if we use a spinlock, the outcome would look something like this, right? (Let flag0 = flag1 = 1)
Time Thread 0 Thread 1
0 flag0--; flag1--;
1 while(flag1 == 0); while(flag2 == 0);
For c) I'm assuming they're referring to a binary semaphore, which is effectively the same thing as a mutex so it'd also result in deadlock.
Is there a mistake in my reasoning? My answers seem suspiciously simple but I don't see how spinlock/semaphores would change anything

Result of 100 concurrent threads, each incrementing variable to 100

I'm writing to ask about this question from 'The Little Book of Semaphores' by Allen B. Downey.
Question from 'The Little Book of Semaphores'
Puzzle: Suppose that 100 threads run the following program concurrently. (if you are not familiar with Python, the for loop runs the update 100 times.):
for i in range(100):
temp = count
count = temp + 1
What is the largest possible value of count after all threads have completed? What is the smallest possible value? Hint: the first question is easy; the second is not.
My understanding is that count is a variable shared by all threads, and that it's initial value is 0.
I believe that the largest possible value is 10,000, which occurs when there is no interleaving between threads.
I believe that the smallest possible value is 100. If line 2 is executed for each thread, they will each have a value of temp = 0. If line 3 is then executed for each thread, they will each set count = 1. If the same behaviour occurs in each iteration, the final value of count will be 100.
Is this correct, or is there another execution path that can result in a value smaller than 100 for count?
The worst case that I can think of will leave count equal to two. It's extremely unlikely that this would ever happen in practice, but in theory, it's possible. I'll need to talk about Thread A, Thread B, and 98 other threads:
Thread A reads count as zero, but then it is preempted before it can do anything else,
Thread B is allowed to run 99 iterations of its loop, and 98 other threads all run to completion before thread A finally is allowed to run again,
Thread A writes 1 to count before—are you ready to believe this?—it gets preempted again!
Thread B starts its 100th iteration. It gets as far as reading count as 1 (just now written by thread A) before thread A finally comes roaring back to life and runs to completion,
Thread B is last to cross the finish line after it writes 2 to count.

Handling Multiple wait operation before entering into critical section in operating system?

I am stuck while solving a counting semaphore problem in Operating system subject.
S is a semaphore initialized to 5.
count = 0 (shared variable)
Assume that the increment operation in line #7 is not atomic.
Now,
1. int counter = 0;
2. Semaphore S = init(5);
3. void parop(void)
4. {
5. wait(S);
6. wait(S);
7. counter++;
8. signal(S);
9. signal(S);
10. }
If five threads execute the function parop concurrently, which of the following program behavior(s) is/are possible?
A. The value of counter is 5 after all the threads successfully complete the execution of parop
B. The value of counter is 1 after all the threads successfully complete the execution of parop
C. The value of counter is 0 after all the threads successfully complete the execution of parop
D. There is a deadlock involving all the threads
what i have understand till now is answer is A and D,because what if all process are executed one by one say(T1->T2->T3->T4->T5) and final value saved will be 5(so A is one of correct options)
Now, why D,because what if all process execute line 5 before 6 and will get blocked.
Now, please can any one help me to understand why B is another correct answer. ?
Thanks in advance,
Hope to here from you soon
Any help will be highly appreciated.
Imagine thread 1 gets to line 7 before any other thread, and line 7 is implemented as three instructions:
7_1: load counter, %r0
7_2: add $1, %r0
7_3: store %r0, counter
For some reason (eg. interrupt, preempted), thread 1 stops at instruction 7_2; so it has loaded the value 0 into register %r0.
Next, thread's 2..5 all run through this sequence, leaving counter at say 4.
Thread 1 is rescheduled, increments %r0 to the value 1 and stores it into counter.

UML activity diagram: fork with guard conditions on the outputs

I have met a semantic problem with guard conditions and fork in activity diagrams. Suppose terminating action A leads to a fork, and the out put of the fork leads to action B and C (that is, this fork has 1 input and 2 outputs). If A has successfully terminated, and guard condition of B is valid while guard condition of C is not, will the whole activity continue to action B and waits for guard condition of C to become true, or neither B nor C would be executed?
Update: consider the following activity example
Suppose that the first time A terminates, guard condition of C is not valid while B does not have guard. Along the merge node, A is exectued the second time. After the second termination of A, guard condition of C becomes eternally valid and it will be executed twice continuously due to the first and second termination of A. Is this correct?
Once A is finished it will emerge a token and the fork will duplicate that. One token goes straight to B which after finalization re-triggers A to infinity. Now, what happens to the token(s) traveling to C? They just queue at the guard. When the guard is opened after some time it lets pass a single token (because C can hold only a single one). When C is finished it will allow another token to enter (if meanwhile multiple tokens have reached) depending additionally on the guard. Basically C can be started as many times as A has been completed before.
N.B. Your implication in the question "guard conditions on the outputs" is wrong. A guard is always on an incoming control flow of an action. The fork will not control the guard, it's the action. And further an action can never have a guard on the output. This is controlled be the action's behavior. When it terminates it will emerge a token on each of its outgoing control flows (so called implicit fork).
Answer to initial question left as common information
Actually when you draw it, the situation is obvious:
The token emerging right from the top fork will be blocked. B will start since the token passed the guard. Because C does not start the lower fork will hang as it needs 2 tokens. So D is not reached. Unless the guard from C will somewhen be unblocked externally.

Difference between racearound condition and deadlock

What is the difference between a dead lock and a race around condition in programming terms?
Think of a race condition using the traditional example. Say you and a friend have an ATM cards for the same bank account. Now suppose the account has $100 in it. Consider what happens when you attempt to withdraw $10 and your friend attempts to withdraw $50 at exactly the same time.
Think about what has to happen. The ATM machine must take your input, read what is currently in your account, and then modify the amount. Note, that in programming terms, an assignment statement is a multi-step process.
So, label both of your transactions T1 (you withdraw $10), and T2 (your friend withdraws $50). Now, the numbers below, to the left, represent time steps.
T1 T2
---------------- ------------------------
1. Read Acct ($100)
2. Read Acct ($100)
3. Write New Amt ($90)
4. Write New Amt ($50)
5. End
6. End
After both transactions complete, using this timeline, which is possible if you don't use any sort of locking mechanism, the account has $50 in it. This is $10 more than it should (your transaction is lost forever, but you still have the money).
This is a called race condition. What you want is for the transaction to be serializable, that is in no matter how you interleave the individual instruction executions, the end result will be the exact same as some serial schedule (meaning you run them one after the other with no interleaving) of the same transactions. The solution, again, is to introduce locking; however incorrect locking can lead to dead lock.
Deadlock occurs when there is a conflict of a shared resource. It's sort of like a Catch-22.
T1 T2
------- --------
1. Lock(x)
2. Lock(y)
3. Write x=1
4. Write y=19
5. Lock(y)
6. Write y=x+1
7. Lock(x)
8. Write x=y+2
9. Unlock(x)
10. Unlock(x)
11. Unlock(y)
12. Unlock(y)
You can see that a deadlock occurs at time 7 because T2 tries to acquire a lock on x but T1 already holds the lock on x but it is waiting on a lock for y, which T2 holds.
This bad. You can turn this diagram into a dependency graph and you will see that there is a cycle. The problem here is that x and y are resources that may be modified together.
One way to prevent this sort of deadlock problem with multiple lock objects (resources) is to introduce an ordering. You see, in the previous example, T1 locked x and then y but T2 locked y and then x. If both transactions adhered here to some ordering rule that says "x shall always be locked before y" then this problem will not occur. (You can change the previous example with this rule in mind and see no deadlock occurs).
These are trivial examples and really I've just used the examples you may have already seen if you have taken any kind of undergrad course on this. In reality, solving deadlock problems can be much harder than this because you tend to have more than a couple resources and a couple transactions interacting.
As always, use Wikipedia as a starting point for CS concepts:
http://en.wikipedia.org/wiki/Deadlock
http://en.wikipedia.org/wiki/Race_condition
A deadlock is when two (or more) threads are blocking each other. Usually this has something to do with threads trying to acquire shared resources. For example if threads T1 and T2 need to acquire both resources A and B in order to do their work. If T1 acquires resource A, then T2 acquires resource B, T1 could then be waiting for resource B while T2 was waiting for resource A. In this case, both threads will wait indefinitely for the resource held by the other thread. These threads are said to be deadlocked.
Race conditions occur when two threads interact in a negatve (buggy) way depending on the exact order that their different instructions are executed. If one thread sets a global variable, for example, then a second thread reads and modifies that global variable, and the first thread reads the variable, the first thread may experience a bug because the variable has changed unexpectedly.
Deadlock :
This happens when 2 or more threads are waiting on each other to release the resource for infinite amount of time.
In this the threads are in blocked state and not executing.
Race/Race Condition:
This happens when 2 or more threads run in parallel but end up giving a result which is wrong and not equivalent if all the operations are done in sequential order.
Here all the threads run and execute there operations.
In Coding we need to avoid both race and deadlock condition.
I assume you mean "race conditions" and not "race around conditions" (I've heard that term...)
Basically, a dead lock is a condition where thread A is waiting for resource X while holding a lock on resource Y, and thread B is waiting for resource Y while holding a lock on resource X. The threads block waiting for each other to release their locks.
The solution to this problem is (usually) to ensure that you take locks on all resources in the same order in all threads. For example, if you always lock resource X before resource Y then my example can never result in a deadlock.
A race condition is something where you're relying on a particular sequence of events happening in a certain order, but that can be messed up if another thread is running at the same time. For example, to insert a new node into a linked list, you need to modify the list head, usually something like so:
newNode->next = listHead;
listHead = newNode;
But if two threads do that at the same time, then you might have a situation where they run like so:
Thread A Thread B
newNode1->next = listHead
newNode2->next = listHead
listHead = newNode2
listHead = newNode1
If this were to happen, then Thread B's modification of the list will be lost because Thread A would have overwritten it. It can be even worse, depending on the exact situation, but that's the basics of it.
The solution to this problem is usually to ensure that you include the proper locking mechanisms (for example, take out a lock any time you want to modify the linked list so that only one thread is modifying it at a time).
Withe rest to Programming language if you are not locking shared resources and are accessed by multiple threads then its called as "Race condition", 2nd case if you locked the resources and sequences of access to shared resources are not defined properly then threads may go long waiting for the resources to use then its a case of "deadlock"

Resources