使用信号量、互斥体或 Auto/ManualResetEvent。
代码
//Initialize semaphore, set it to BLOCK
ManualResetEvent sema = new ManualResetEvent(false);
void Main()
{
var x = new Thread(Delegate);
//Request the system to start the thread.
//This doesn't mean the CPU will immediately run Delegate method
//but eventually it will do
x.Start(sema);
//Stop here and don't do anything on this thread until the semaphore is FREE
sema.WaitOne();
[continued main thread]
}
void Delegate(Semaphore sema){
//Unblock the semaphore
sema.Set(1);
[your code here]
}
深入解释
多线程背后的原则之一是非确定性。如果您不使用正确的技术,如上所述,您无法预测在多个线程中完成的操作的行为如果您有这样的方法
void Main()
{
A();
B();
C();
}
那么你确定 B 永远不会在 A 之前或 C 之后执行。这同样不适用于多线程。
void Main()
{
new Thread(A).Start();
new Thread(B).Start();
new Thread(C).Start();
D();
}
您确定运行 B 的线程在运行 A 的线程之后是 started,但在多线程中这意味着不同的东西。在 MSDN 和每本编程书籍中,启动线程仅仅意味着请求操作系统在内核中分配适当的设施以支持多线程。如果这样做了(线程被正确创建并安排执行),则该方法返回而不会出错。操作系统可能会以任意顺序运行三个线程,具体取决于多种因素。
因此,如果您将它们调试到控制台(认为每个都执行Console.WriteLine("Hello, I'm thread A/B/C"),您可以在不同的执行中获得任何顺序:A,B,C;A,C,B;B,C,A 等等。
所以你现在想确定,但真的,真的确定,一个特定的或每个线程在运行 D 之前已经真正启动了。事实上,在许多单核 CPU 的情况下,操作系统应该运行 @每个线程之前的 987654329@ 方法。这也是不可预知的!所以在无法预测 A、B 和 C 什么时候运行之后,你就无法预测 D 什么时候运行了!!
显式同步是一种强制暂停代码执行并等待事件发生的技术。信号量释放所描述的事件取决于上下文,所以在你的情况下,你只是告诉主线程“等待委托开始,然后做任何你想做的事情”:)
替代的、低效的方法
使用信号量只是通过无限循环执行以下操作的一种有效方法
volatile bool threadStarted = false;
void Main()
{
var x = new Thread(Delegate);
x.Start();
while (!threadStarted);
[continued main thread]
}
void Delegate(Semaphore sema){
threadStarted = true;
[your code here]
}
使用信号量不会简单地浪费 CPU 来不断检查某个标志是低还是高