How to replace this semaphore with a monitor?

In my previous question, someone meant that using Semaphores was expensive in C # compared to using a monitor. So I ask about this, how to replace the semaphore in this code with a monitor?

I need function1 to return its value after function2 (in a separate thread) has completed. I replaced Semaphore.WaitOne with Monitor.Wait and Semaphore.Release with Monitor.PulseAll , but PulseAll started before Wait , causing the program to hang. Any idea how to avoid this race condition?

 Semaphore semaphore = new Semaphore(0,1); byte b; public byte Function1() { // new thread starting in Function2; semaphore.WaitOne(); return b; } public void Function2() { // do some thing b = 0; semaphore.Release(); } 
+4
source share
2 answers

You can do this with WaitHandle instead of a semaphore. This would be the easiest alternative and better than Semaphore:

 ManualResetEvent manualResetEvent = new ManualResetEvent(false); byte b; public byte Function1() { // new thread starting in Function2; manualResetEvent.WaitOne(); return b; } public void Function2() { // do some thing b = 0; manualResetEvent.Set(); } 
+9
source

@Reed provides an elegant solution if you need to wait for multiple threads.

You might not want to use Monitor for this. As @Reed noted, an event would be enough and provide the cleanest and most understandable solution that meets the requirements of your code.
The overhead of using real operating system synchronization primitives, most likely, will not matter in your case and using, for example, Monitor will provide only decreasing returns due to much higher complexity.

With that said, an implementation using Monitor and signaling is presented here.

You can use the lock-protected bool flag to indicate that you are finished and cannot wait in this case. (A)
If you really start a new thread in Function2() , where the comments point and use lock() around WaitOne() and Release() , you don't need a flag at all. (IN)

A using the flag:

 class Program { static object syncRoot = new object(); //lock implies a membar, no need for volatile here. static bool finished = false; static byte b; public static byte Function1() { lock (syncRoot) { //Wait only if F2 has not finished yet. if (!finished) { Monitor.Wait(syncRoot); } } return b; } static public void Function2() { // do some thing b = 1; lock (syncRoot) { finished = true; Monitor.Pulse(syncRoot); } } static void Main(string[] args) { new Thread(Function2).Start(); Console.WriteLine(Function1()); } } 

B, starting the thread from Function1 :

 class Program { static object syncRoot = new object(); static byte b; public static byte Function1() { lock (syncRoot) { // new thread starting in Function2; new Thread(Function2).Start(); Monitor.Wait(syncRoot); } return b; } static public void Function2() { // do some thing b = 1; //We need to take the lock here as well lock (syncRoot) { Monitor.Pulse(syncRoot); } } static void Main(string[] args) { Console.WriteLine(Function1()); } } 
+2
source

Source: https://habr.com/ru/post/1305869/


All Articles