Releasesemaphore Does Not Release the Semaphore

ReleaseSemaphore does not release the semaphore

the problem happens in the following case:

the main thread resumes the worker threads:

  for (int i=0 ; i<numCPU ; i++)
{
if (WaitForSingleObject(semaphore,1) == WAIT_TIMEOUT)
printf("Timed out !!!\n");
ResumeThread(ids[i]);
}

the worker threads do their work and release the semaphore:

  for (int i=1 ; i<LOOP ; i++)
x = sqrt((float)i*x);
while (ReleaseSemaphore(semaphore,1,NULL) == FALSE)

the main thread waits for all worker threads and resets the semaphore:

  for (int i=0 ; i<numCPU ; i++)
WaitForSingleObject(semaphore,INFINITE);
ReleaseSemaphore(semaphore,numCPU,NULL);

the main thread goes into the next round, trying to resume the worker threads (note that the worker threads haven't event suspended themselves yet! this is where the problem starts... you are trying to resume threads that aren't necessarily suspended yet):

  for (int i=0 ; i<numCPU ; i++)
{
if (WaitForSingleObject(semaphore,1) == WAIT_TIMEOUT)
printf("Timed out !!!\n");
ResumeThread(ids[i]);
}

finally the worker threads suspend themselves (although they should already start the next round):

  SuspendThread(ids[(int) lpParameter]);

and the main thread waits forever since all workers are suspended now:

  for (int i=0 ; i<numCPU ; i++)
WaitForSingleObject(semaphore,INFINITE);

here's a link that shows how to correctly solve producer/consumer problems:

http://en.wikipedia.org/wiki/Producer-consumer_problem

also i think critical sections are much faster than semaphores and mutexes. they're also easier to understand in most cases (imo).

Why semaphore is released but WaitForSingleObject() still stuck?

Well, I solved it myself. The reason is that I used CreateSemaphore again after creating the thread, making the player thread visiting different semaphores as the monitor thread... Sorry for my stupidness, and thank you for telling me so much!

How does a semaphore release from another thread?

Consider

var semaphore = new SemaphoreSlim(2);

It means that the semaphore at this moment of time has only 2 executions slots, but you have to keep in mind that it is only the initial number of executions slots (for requests to be granted concurrently).

So, if we will spawn A,B,C thread into a semaphore with 2 executions slots the first two threads will be executed and the C thread will be queued until someone else in the code will signal the semaphore it is OK to add one more execution slot.

When someone will say its OK to execute the next thread in the queue, the C will be executed regardless to the others thread.


Some technical example:

(As I saw in @dmitri-nesteruk's course)

The total number of available executions slots is being represented by CurrentCount.

Each time a thread wanted to be executed it asks the semaphore if it has an available execution slot (with CurrentCount > 0), if true - feel free to get yourself executed, if not get inside the queue.

What makes the semaphore so confusing is the fact that CurrentCount value can be either decreased or increased.

  • Its decreases by one each time the Wait() has been called by a
    thread, which means that there is one less available execution slot
    and the a thread is being executed.

  • Its increases by one (or more) each time the Release(1) has been
    called somewhere else in the code, which means that there is one more
    available execution slot so the first thread in the semaphore inside
    queue is being executed (it won't terminate the others).

In this example the we spawn 3 threads, but the only first two will be executed until someone will say to the semaphore that he can release another execution slot by increasing the CurrentCount with Release(1).

for (int i = 0; i < 3 ; i++)
{
Task.Factory.StartNew(() =>
{
Console.WriteLine($"Spawning task: {Task.CurrentId}");
semaphore.Wait(); //CurrentCount--
Console.WriteLine($"Executing task: {Task.CurrentId}");
});
}

while (semaphore.CurrentCount <= 2)
{
Console.ReadKey();
Console.WriteLine("Key pressed");
semaphore.Release(1); //CurrentCount++
}

The Output:

Spawning task: A
Spawning task: B
Spawning task: C
Executing task: A
Executing task: B
.....
Key pressed
Executing task: C

Thread Interruptded Exception, release semaphore resources

You could try to use List like this:

List<Semaphore> acquired = new ArrayList<>(2);
while(!Thread.currentThread().isInterrupted) {
try{
A.acquire(2);
acquired.add(A);
B.acquire(2);
acquired.add(B);
//some-stuff
} catch(InterruptedException ex){}
finally{
for (Semaphore s : acquired) {
s.release(2);
}
s.clear();
}
}


Related Topics



Leave a reply



Submit