I thought that the following code would let all the 10 threads run, two at a time, and then print "done" after Release()
is called 10 times. But that's not what happened:
int count = 0;
Semaphore s = new Semaphore(2, 2);
for (int x = 0; x < 10; x++)
{
Thread t = new Thread(new ThreadStart(delegate()
{
s.WaitOne();
Thread.Sleep(1000);
Interlocked.Increment(ref count);
s.Release();
}));
t.Start(x);
}
WaitHandle.WaitAll(new WaitHandle[] { s });
Console.WriteLine("done: {0}", count);
output:
done: 6
If the only way to implement the functionality I'm looking for is to pass an EventWaitHandle
to each thread and then do a WaitAll()
on an array of those EventWaitHandles
, then what's the meaning of doing a WaitAll()
on an array of only a semaphore? In other words, when does the waiting thread unblock?
The post (sem_post()) operation increments the semaphore; the wait (sem_wait()) operation decrements it. If you wait on a semaphore that is positive, you will not block. Waiting on a nonpositive semaphore will block until some other thread executes a post. It is valid to post one or more times before a wait.
The wait command P(S) decrements the semaphore value by 1. If the resulting value becomes negative then P command is delayed until the condition is satisfied. The V(S) i.e. signals operation increments the semaphore value by 1.
" Semaphore S is an integer variable that is accessed through standard atomic operations i.e. wait() and signal().
A semaphore is a signaling mechanism, and a thread that is waiting on a semaphore can be signaled by another thread. It uses two atomic operations, 1) Wait, and 2) Signal for the process synchronization. A semaphore either allows or disallows access to the resource, which depends on how it is set up.
WaitHandle.WaitAll
just waits until all the handlers are in signalled state.
So when you call WaitHandle.WaitAll
on one WaitHandle
it works the same as you call s.WaitOne()
You can use, for example, the following code to wait for all the started threads, but allow two threads to run in parallel:
int count = 0;
Semaphore s = new Semaphore(2, 2);
AutoResetEvent[] waitHandles = new AutoResetEvent[10];
for (int x = 0; x < 10; x++)
waitHandles[x] = new AutoResetEvent(false);
for (int x = 0; x < 10; x++)
{
Thread t = new Thread(threadNumber =>
{
s.WaitOne();
Thread.Sleep(1000);
Interlocked.Increment(ref count);
waitHandles[(int)threadNumber].Set();
s.Release();
});
t.Start(x);
}
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("done: {0}", count);
WaitHandle.WaitAll(new WaitHandle[] { s });
waits just like s.WaitOne();
. It enters at the first opportunity. You seem to expect this call to wait for all other semaphore operations but there is no way the operating system can tell the difference. This command might well be the first that is granted access to the semaphore.
I think what you need is the Barrier
class. It is made for fork-join-style parallelism.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With