Wait for another stream

So, I have this program that is trying to establish a connection between two different threads, thread1 and thread2.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace Project1 { class Class1 { public static void thread1() { Console.WriteLine("1"); Console.WriteLine("t2 has printed 1, so we now print 2"); Console.WriteLine("t2 has printed 2, so we now print 3"); } public static void thread2() { Console.WriteLine("t1 has printed 1, so we now print 1"); Console.WriteLine("t1 has printed 2, so we now print 2"); Console.WriteLine("t1 has printed 3, so we now print 3"); } public static void Main() { Thread t1 = new Thread(new ThreadStart(() => thread1())); Thread t2 = new Thread(new ThreadStart(() => thread2())); t1.Start(); t2.Start(); t2.Join(); t1.Join(); } } } 

However, I want this to happen so that this line:

 Console.WriteLine("1"); 

... is executed first, and thread2 just waits for this line to execute. Then and only then will it print:

 Console.WriteLine("t1 has printed 1, so we now print 1"); 

After this line is printed, then and only then this line:

 Console.WriteLine("t2 has printed 1, so we now print 2"); 

... to be printed, etc. Therefore, I want to change the code so that the threads communicate with each other, so that the lines are printed in the following order:

  Console.WriteLine("1"); // from t1 Console.WriteLine("t1 has printed 1, so we now print 1"); // from t2 Console.WriteLine("t2 has printed 1, so we now print 2"); // from t1 Console.WriteLine("t1 has printed 2, so we now print 2"); // from t2 Console.WriteLine("t2 has printed 2, so we now print 3"); // from t1 Console.WriteLine("t1 has printed 3, so we now print 3"); // from t2 

I understand what the lock does, but only applies if two different threads are running on the same function. However, the two functions are different here, and therefore I cannot use the lock here.

Any ideas?

+4
source share
4 answers

It looks like you need Monitor.Wait and Monitor.Pulse . There is a free e-book on Threading (maybe a lot, but it helped me).

You can use a static object to lock, and then your threads call Monitor.Pulse to signal that they are "done with a turn" and Monitor.Wait to "wait for the next turn." Here is an example implementation using your base code:

 public class Class1 { // Use this to syncrhonize threads private static object SyncRoot = new object(); // First "turn" goes to thread 1 private static int threadInControl = 1; public static void thread1() { lock(SyncRoot) // Request exclusive access to SyncRoot { Console.WriteLine("1"); GiveTurnTo(2); // Let thread 2 have a turn WaitTurn(1); // Wait for turn to be given to thread 1 Console.WriteLine("t2 has printed 1, so we now print 2"); GiveTurnTo(2); // Let thread 2 have a turn WaitTurn(1); // Wait for turn to be given to thread 1 Console.WriteLine("t2 has printed 2, so we now print 3"); GiveTurnTo(2); // Let thread 2 have a turn } } public static void thread2() { lock(SyncRoot) // Request exclusive access to SyncRoot { WaitTurn(2); // Wait for turn to be given to thread 2 Console.WriteLine("t1 has printed 1, so we now print 1"); GiveTurnTo(1); // Let thread 1 have a turn WaitTurn(2); // Wait for turn to be given to thread 2 Console.WriteLine("t1 has printed 2, so we now print 2"); GiveTurnTo(1); // Let thread 1 have a turn WaitTurn(2); // Wait for turn to be given to thread 2 Console.WriteLine("t1 has printed 3, so we now print 3"); GiveTurnTo(1); // Let thread 1 have a turn } } // Wait for turn to use SyncRoot object public static void WaitTurn(int threadNum) { // While( not this threads turn ) while (threadInControl != threadNum) { // "Let go" of lock on SyncRoot and wait utill // someone finishes their turn with it Monitor.Wait(SyncRoot); } } // Pass turn over to other thread public static void GiveTurnTo(int nextThreadNum) { threadInControl = nextThreadNum; // Notify waiting threads that it someone else turn Monitor.Pulse(SyncRoot); } public static void void Main() { Thread t1 = new Thread(new ThreadStart(() => Class1.thread1())); Thread t2 = new Thread(new ThreadStart(() => Class1.thread2())); t1.Start(); t2.Start(); t2.Join(); t1.Join(); } } 

Regarding the use of the lock keyword , this is not limited to synchronization within the same function. A lock "guarantees" exclusive access to a resource (object) to one thread (by exceptional, I mean that only one thread can get a lock on this resource at a time, blocking does not prevent other threads from simply accessing the object itself).

To simplify it, lock(someObject) is like a thread entering a line, to use someOject , and then until all other threads before it end before continuing. A thread ends its “turn” when it leaves the scope of the lock statement (unless you add things like Monitor.Pulse or Monitor.Wait ).

+8
source

Use ManualResetEvent. Wait for it in thread 2 and set it to thread1 after Console.WriteLn () http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

+3
source
 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace Project1 { class Class1 { private static ManualResetEvent mre1 = new ManualResetEvent(false); private static ManualResetEvent mre2 = new ManualResetEvent(false); public static void thread1() { Console.WriteLine("1"); mre2.Set(); mre1.WaitOne(); Console.WriteLine("t2 has printed 1, so we now print 2"); mre2.Set(); mre1.WaitOne(); Console.WriteLine("t2 has printed 2, so we now print 3"); } public static void thread2() { mre2.WaitOne(); Console.WriteLine("t1 has printed 1, so we now print 1"); mre1.Set(); mre2.WaitOne(); Console.WriteLine("t1 has printed 2, so we now print 2"); mre1.Set(); mre2.WaitOne(); Console.WriteLine("t1 has printed 3, so we now print 3"); } public static void Main() { Thread t1 = new Thread(new ThreadStart(() => thread1())); Thread t2 = new Thread(new ThreadStart(() => thread2())); t1.Start(); t2.Start(); while (true) { Thread.Sleep(1); } } } } 

Thanks guys. I think I have a solution now!

+2
source

In the example in the Two-Way Signaling and Racing section of the “Alarm with Standby and Momentum” section of Mr. Joe Albahari’s Advanced Threading Tutorial:

 static readonly object locker = new object(); private static bool ready, go; public static void Thread1() { IEnumerable<Action> actions = new List<Action>() { () => Console.WriteLine("1"), () => Console.WriteLine("t2 has printed 1, so we now print 2"), () => Console.WriteLine("t2 has printed 2, so we now print 3") }; foreach (var action in actions) { lock (locker) { while (!ready) Monitor.Wait(locker); ready = false; go = true; Monitor.PulseAll(locker); action(); } } } public static void Thread2() { IEnumerable<Action> actions = new List<Action>() { () => Console.WriteLine("t1 has printed 1, so we now print 1"), () => Console.WriteLine("t1 has printed 2, so we now print 2"), () => Console.WriteLine("t1 has printed 3, so we now print 3") }; foreach (var action in actions) { lock (locker) { ready = true; Monitor.PulseAll(locker); while (!go) Monitor.Wait(locker); go = false; action(); } } } private static void Main(string[] args) { Thread t1 = new Thread(new ThreadStart(() => Thread1())); Thread t2 = new Thread(new ThreadStart(() => Thread2())); t1.Start(); t2.Start(); t2.Join(); t1.Join(); } 
+1
source

All Articles