等待另一个线程
所以我有这个程序试图建立两个不同的线程,thread1和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();
}
}
}
不过,我希望它发生,使得该行:
Console.WriteLine("1");
...最先被执行,而线程2只等待被执行这条线。那时,也只有这样才打印:该行打印
Console.WriteLine("t1 has printed 1, so we now print 1");
后,再然后才将这一行:
Console.WriteLine("t2 has printed 1, so we now print 2");
...得到印刷,等等。所以我想更改代码,使线程相互沟通,使线路得到印刷顺序:
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
我明白做什么锁,但它仅适用,如果两个不同的线程是运行在相同的功能上。但是,在这里,这两个函数是不同的,因此我不能在这里使用锁。
任何想法?
使用ManualResetEvent。在线程2等待它和Console.WriteLn(之后将其设置在线程1) http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx
它看起来像你需要Monitor.Wait和Monitor.Pulse。线程上有一个free eBook(可能有很多,但这个帮助我)。
你可以使用一个静态对象来锁定,然后让你的线程调用Monitor.Pulse
来表示他们“完成了他们的转身”,Monitor.Wait
“等待他们的下一个回合”。下面是使用你的基本代码示例实现:
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's someone else's 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();
}
}
至于使用lock keyword,它不局限于同步的相同函数内。锁“保证”对一个资源(对象)对单个线程的独占访问(独占,我的意思是一次只有一个线程可以获得该资源上的锁,锁不会阻止其他线程简单地访问该对象本身) 。
为了简化它,lock(someObject)
就像是一个线程正在使用someOject
,然后等待,直到它前面的所有其他线程都已经完成轮到它再继续。线程结束其“转”,当它离开锁语句的范围(除非你添加像Monitor.Pulse
或Monitor.Wait
的东西)。
+1链接到一本梦幻般的书 – Kell 2012-08-16 15:51:52
乔恩,非常感谢这个提示! – 2012-08-16 16:01:16
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);
}
}
}
}
谢谢你们。我想我现在有解决方案!
如果你已经找到了解决问题的答案(如果你愿意的话,它可以是你自己的解决方案,尽管看起来@凯尔的回答是让你在这里的答案),请在此页面接受解决方案。 – 2012-08-16 16:37:09
从包含在高级线程教程由乔阿尔巴哈利先生等待和脉冲部分信令的Two-Way Signaling and Races节给出的示例:
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();
}
嘿,谢谢一堆! – 2012-08-16 16:12:17
采用'Monitor.Pulse()'和'Monitor.Wait()'思路的好方法,并减少添加更多操作所需的代码量。 – 2012-08-16 16:41:18
只是在锁记,因为我下面提到的,你的线程不需要处于相同的功能。只要在同一进程中运行,锁可用于同步线程**。如果您尝试同步不同进程中的线程(例如同步两个不同的程序),则需要使用Mutex。 – 2012-08-16 16:34:25