Aren't wait and signal conditional variables to signify request and release?
This link states that semaphores do not have coniditonal variables while monitors do.
According to the same site,
The conditional variable allows a process to wait inside the monitor
and allows a waiting process to resume immediately when the other
process releases the resources.
Isn't that the same procedure in a semaphore?
The difference here is that semaphore is a stateful object, while condition variable is stateless.
The idea is that sometime you have a very complex state (that cannot be represented by a simple counter like a semaphore) and you want to wait for that state to change. That is the reason why condition variables are used with mutexes - a mutex is required to protect the change of that state and allows waiting for a change without losing notifications.
Internally some semaphore implementations are based on condition variables - in this case counter is a protected state that is going to change. But such implementations are not very effecient as modern OS have better ways to implement semaphores.
If you want to know how condition variables and semaphores can be implemented, you can read my answer here.
Related
How could I delay a background queue's execution, without using sleep? Further, how could I interrupt that delay if needs be?
The docs for RunLoop suggest a while loop around the function run with a custom condition in the while loop. But how would I setup a timer to toggle the while loops execution?
You can suspend custom dispatch queues (but not global queues nor main queue). That stops new tasks from starting on that queue, but it does not affect things already running on that queue. You can resume to start running items that had previously been dispatched to the queue, but had not yet started.
GCD also provides a native mechanism to cancel a particular work item, and dispatch it again later when you want execution to resume. Note that cancel does not perform preemptive cancellation, but rather only sets a Boolean, isCancelled, which your dispatched task would need to periodically check and manually exit.
(If you want to cancel tasks on a queue, you might consider OperationQueue, as that has more graceful cancelation capabilities than dispatch queues. Or you might consider the “structured concurrency” of async-await of Swift concurrency, which also has cancelation built-in.)
Now, while GCD does not have a notion of “suspending” a task dispatched to a background thread, you might be able to jury-rig something something with a very careful use a semaphores. But the details would vary greatly based upon your implementation, so it is hard to advise further without more details.
You asked:
The docs for RunLoop suggest a while loop around the function run with a custom condition in the while loop.
As a general rule, anything that involves spinning in a while loop is to be avoided. It is s very inefficient pattern and is to be avoided. Many years ago (e.g. before GCD, before URLSession, etc.), this spin-on-run-loop pattern was not unheard of (e.g., it was the go-to technique for running NSURLConnection on a background thread), but it is an anachronism nowadays. It is an inefficient approach; an anti-pattern.
The main reason for using semaphores is to prevent the producer-consumer problem.
But I wonder what would happen if a process gets preempted while executing wait operation and another process also executes wait operation.
Let's take
S value as 1.
What if while executing Wait(), S value is loaded into register reg as 1.
now S value is decremented.
Now reg is 0.
And now if another process wants to execute the wait to access the critical section
it considers S value as 1.
loads reg as 1.
and again decrements.
reg is 0.
Now both processes enter the critical section.
The code for the wait function is
Down(Semaphore S){
S.value=S.value-1;
if(S.value<0)
{
put PCB in suspended list;
sleep;
}
else
return;
}
The code for the signal function is
Signal(Semaphore S){
S.value=S.value+1;
if(S.value<=0)
{
Select a process from suspendend list;
wakeup();
}
}
isn't semaphore variable also a critical section variable as it is common for two or many processes? how can we prevent such race conditions?
You are correct that if the code for semaphore operations is as given above, there is indeed a risk that something bad could happen if a thread gets preempted in the middle of implementing an operation. The reason that this isn’t a problem in practice is that the actual implementations of semaphore operations are a bit more involved than what you gave.
Some implementations of semaphores, for example, will begin by physically disabling the interrupt mechanism on the machine to ensure that the current thread cannot possibly be preempted during execution of the operation. Others are layered on top of other synchronization primitives that use similar techniques to prevent preemption. Others might use other mechanisms besides disabling interrupts that have the same effect of ensuring that the process can’t be halted midway in the middle of performing the needed synchronization, or at least, ensuring that any places where preemption can occur are well-marked and properly thought through.
Hope this helps!
I have a doubt regarding UVM. Let's think I have a DUT with two interfaces, each one with its agent, generating transactions with the same clock. These transactions are handled with analysis imports (and write functions) on the scoreboard. My problem is that both these transactions read/modify shared variables of the scoreboard.
My questions are:
1) Have I to guarantee mutual exclusion explicitly though a semaphore? (i suppose yes)
2) Is this, in general, a correct way to proceed?
3) and the main problem, can in some way the order of execution be fixed?
Depending on that order the values of shared variables can change, generating inconsistency. Moreover, that order is fixed by specifications.
Thanks in advance.
While SystemVerilog tasks and functions do run concurrently, they do not run in parallel. It is important to understand the difference between parallelism and concurrency and it has been explained well here.
So while a SystemVerilog task or function could be executing concurrently with another task or function, in reality it does not actually run at the same time (run time context). The SystemVerilog scheduler keeps a list of all the tasks and functions that need to run on the same simulation time and at that time it executes them one-by-one (sequentially) on the same processor (concurrency) and not together on multiple processors (parallelism). As a result mutual exclusion is implicit and you do not need to use semaphores on that account.
The sequence in which two such concurrent functions would be executed is not deterministic but it is repeatable. So when you execute a testbench multiple times on the same simulator, the sequence of execution would be same. But two different simulators (or different versions of the same simulator) could execute these functions in a different order.
If the specifications require a certain order of execution, you need to ensure that order by making one of these tasks/functions wait on the other. In your scoreboard example, since you are using analysis port, you will have two "write" functions (perhaps using uvm_analysis_imp_decl macro) executing concurrently. To ensure an order, (since functions can not wait) you can fork out join_none threads and make one of the threads wait on the other by introducing an event that gets triggered at the conclusion of the first thread and the other thread waits for this event at the start.
This is a pretty difficult problem to address. If you get 2 transactions in the same time step, you have to be able to process them regardless of the order in which they get sent to your scoreboard. You can't know for sure which monitor will get triggered first. The only thing you can do is collect the transactions and at the end of the time step do your modeling/checking/etc.
Semaphores only help you if you have concurrent threads that take (simulation) time that are trying to access a shared resource. If you get things from an analysis port, then you get them in 0 time, so semaphores won't help you here.
So to my understanding, the answer is: compiler/vendor/uvm cannot ensure the order of execution. If you need to ensure the order which actually happen in same time step, you need to use semaphore correctly to make it work the way you want.
Another thing is, only you yourself know which one must execute after the other if they are in same simulation time.
this is a classical race condition where the result depends upon the actual thread order...
first of all you have to decide if the write race is problematic for you and/or if there is a priority order in this case. if you dont care the last access would win.
if the access isnt atomic you might need a semaphore to ensure only one access is handled at a time and the next waits till the first has finished.
you can also try to control order by changing the structure or introducing thread ordering (wait_order) or if possible you remove timing at all (here instead of directly operating with the data you get you simply store the data for some time and then later you operate on it.
My understanding is that the queue based approach to concurrency can be implemented without locking. But I see lots of synchronized keywords in the Actor.scala file (looking at 2.8.1). Is it synchronized, is it necessary, would it make a difference if there was an implementation that was not synchronized?
Apparently the question wasn't clear enough: my understanding is that this can be implemented with a non-blocking queue. Why was it not done so? Why use the synchronized keyword anywhere in here? There may be a very good reason, or it might be just because that's the way it was done and it's not necessary. I was just curious which.
The point is that the reactions, which you write in the "act" method, do not need to concern themselves with synchronization. Also, assuming that you do not expose the actor's state, your program will be fully thread safe.
That is not to say that there is no sync at all: synchronization is absolutely necessary [1] to implement read/write access to the actor's mailbox (i.e. the sending and receiving of messages) and also to ensure the actor's private state is consistent across any subsequent reacts.
This is achieved by the library itself and you, the user, need not concern yourself with how it is done. Your state is safe (you don't even need to use volatile fields) because of the JMM's happens before guarantees. That is, if a main-memory write happens before a sync point, then any read occurring after a sync will observe the main memory state left by the write.
[1] - by "synchronization", I mean some mechanism to guarantee a happens-before relationship in the Java Memory Model. This includes the synchronized keyword, the volatile modifier and/or the java.util.concurrent locking primitives
Why use binary semaphores when the same functionality can be achieved with a simple variable ?
Because a semaphore isn't a simple variable, it's a larger construct than that.
Specifically, with a counting semaphore (which a binary semaphore is, effectively, with a count of 1), there's the added capability of blocking any process/thread that tries to increment the semaphore above its maximum value.
Semaphores also have the additional facility that their state is changed "atomically", which means that the underlying memory is surrounded by logic to ensure that the CPU caches and such are flushed, and that when the value is changed, it's changed for "everyone". This is particularly important on modern multi-core processors.
The semaphore is appropriate to use when you are trying to guard a shared resource from over use. A binary semaphore is perfect for resources that can only be used by one process/thread at a time.
Because a variable does not work across processes. A system semaphore does.
A number of reasons. Because a semaphore is provided by the operating system, it can...
a) be shared among multiple processes.
b) be used to block processes in waiting, instead of busily waiting.
c) actually work. A variable shared by multiple threads, or in shared memory space for multiple processes, won't give you the safety of a semaphore, because you never know when your thread/process will lose control. When you acquire a binary semaphore, you KNOW you are the only thread/process in that code section, the OS guarantees that.
I recommend you read a book on this, it's kinda a silly question :) no offence!
Semaphores atomic operations are essential to multi-threaded code, otherwise there would be no way to determine which thread went first. For example if you have two threads that process email requests and you want each person to only get one email; you need to determine if an email request has already been processed. Without a semaphore here is what happens:
Thread A checks if email[0] has been read, it has not
Thread B checks if email[0] has been read, it has not
Thread A sends email[0] and marks it as done
Thread B sends email[0] and marks it as done
For the user the email has been sent twice because both threads saw it as not processed. Now with a semaphore here is what happens to the email:
Thread A marks email[0] as in progress via a semaphore
Thread B checks email[0] and sees the semaphore is marked
Thread A sends email[0] and marks it as done then unmarks the semaphore
With the semaphore only one thread will process the email.
Actually, Semaphore is not like a single variable. As explained above it comes with so many advantages. You can read the book, "The Little Book of Semaphores, 2nd Edition,By Allen B. Downey" for more details about semaphores.
A semaphore restricts access across processes, while a variable, even one that is global to your application, cannot do the same system-wide.
Besides, why reinvent the wheel? You'd have to handle all of the implementation yourself with a variable, whereas with a semaphore, the functionality is already provided by the operating system and guaranteed to work.
Lets assume a simple way of implementing a resource protection could be done by using a variable i.e. a BOOLEAN. I'll give an example:
while {resource_protected == TRUE}
{
// resource is protected
}
Now we can protect a resource by setting resource_protected == TRUE.
To check if the resource is available we just use something like this:
if {resource_protected == FALSE}
{ // <---- rescheduling possible here!
resource_protected == TRUE; // protect resource
}
else
{
//try again later
}
But there are two problems with this method. First, this creates a busy wait thus the processor is not free to do other stuff. Second, and more important, this active process can be rescheduled (moved to waiting queue) after it checks the BOOLEAN but before it protects the resource by setting the BOOLEAN to TRUE thus creating the illusion for other processes that the resource is still free, because the BOOLEAN is not yet set. This allows an other process to claim the resource. A now active process (promoted from waiting queue to running due to rescheduling) protects the resource by setting the BOOLEAN to TRUE (because it has not been set by the rescheduled process in the waiting queue). Now this active process is rescheduled and the previous process becomes active again it will set the BOOLEAN to TRUE (although it has been set to TRUE already by the second process) because it has already checked the BOOLEAN. Now both processes claim the same resource and you will die an old man trying to debug this mess.
With semaphores you can avoid this ugly ugly mess because it allows atoms. Atoms are sets of instructions which appear indivisible from the perspective of other processes. Thus avoiding such mishaps through bad rescheduling.