I am writing a simple program in which there are several threads, and each of them in turn gets access to a shared resource and performs some kind of action. I understand that Wait () frees the blocking object, and blocks the execution of the thread until another thread calls Pulse (), well, Pulse () allows the thread in Wait () to execute further.

Resource

class Sourse { object objLock = new object(); public void toDo(string name) { lock (objLock) { Monitor.Pulse(objLock); Console.WriteLine($"Поток {name} получил доступ и выполняется."); Monitor.Wait(objLock); } } } 

My threads

 class MyThread { Thread thrd; static Sourse srs = new Sourse(); public MyThread(string name) { thrd = new Thread(this.Run); thrd.Name = name; thrd.Start(); } public void Run() { while (true) { srs.toDo(thrd.Name); Thread.Sleep(1000); } } } 

And the entry point into the program:

 class Program { static void Main(string[] args) { MyThread first = new MyThread("1"); MyThread second = new MyThread("2"); MyThread third = new MyThread("3"); } } 

If I organize the code in the way I showed above - several threads are executed simultaneously, the actions are not synchronized in any way. If I write this way:

 lock (objLock) { Monitor.Wait(objLock); Console.WriteLine($"Поток {name} получил доступ и выполняется."); Monitor.Pulse(objLock); } 

That is, of course, all threads will be blocked without performing any actions, and everyone will stand in wait. The poorly needed result I need is achieved if I organize the resource as follows:

  bool key = true; lock (objLock) { if(key == true) { Console.WriteLine($"Поток {name} получил доступ и выполняется"); key = false; Monitor.Wait(objLock); } else { key = true; Monitor.Pulse(objLock); } } 

but such a record looks like a crutch crutch, and moreover, does not meet all the requirements, since at the start of the program, 2 threads immediately get access and execute simultaneously, and this should not be the case. The question is: how to implement sequential access from multiple threads to a shared resource so that the resource is always available to only one thread? Is it possible to achieve the result I need without such booleans?

    1 answer 1

    You already have a lock that is using Monitor inside. Manual work through Monitor you interfere with it. Just remove the manual calls and it will work.

     class Sourse { object objLock = new object(); public void toDo(string name) { lock (objLock) { Console.WriteLine($"Поток {name} получил доступ и выполняется."); } } } 
    • try it in practice and see what happens - Alexey Fedotov
    • @ Alexey Fedotov you will not believe, tried. of the lock block associated with a single objLock object at a time, no more than one thread enters. Did you expect any other behavior? - PashaPash
    • one
      @Alexey Fedotov want a visual result - transfer the "work" (call Thread.Sleep (1000);) inside this lock, so that the resource is locked for a long time, and not only while the message is displayed. - PashaPash
    • one
      @Alexey Fedotov is because you are blocking only for the duration of the output to the console. Move the Thread.Sleep inside the lock. - PashaPash
    • 2
      @ Alexey Fedotov for the ordering of some actions. One thread informs the other that it has completed some work, and the other thread can begin. For example, you have an infinite loop that waits for messages in the List <> collection. From another thread, you add something to the list and send a signal to the stream with an infinite loop, and it starts processing the message. - Zergatul