为什么局部变量不能在C#中出现波动?

public void MyTest() { bool eventFinished = false; myEventRaiser.OnEvent += delegate { doStuff(); eventFinished = true; }; myEventRaiser.RaiseEventInSeperateThread() while(!eventFinished) Thread.Sleep(1); Assert.That(stuff); } 

为什么eventFinished不能变得不稳定并且重要吗?

在我看来,在这种情况下,编译器或运行时可能会变得聪明,并且在while循环中“知道”eventFinished只能为false。 特别是当您考虑提升变量作为类的成员生成的方式以及委托作为同一类的方法时,从而剥夺了eventFinished曾经是局部变量这一事实的优化。

存在一个线程原语, ManualResetEvent来完成这个任务 – 你不想使用布尔标志。

这样的事情应该做的工作:

 public void MyTest() { var doneEvent = new ManualResetEvent(false); myEventRaiser.OnEvent += delegate { doStuff(); doneEvent.Set(); }; myEventRaiser.RaiseEventInSeparateThread(); doneEvent.WaitOne(); Assert.That(stuff); } 

关于对局部变量缺乏对volatile关键字的支持,我不认为理论上在C#中可能无法实现这一点。 最有可能的是,它不受支持仅仅因为在C#2.0之前没有使用这样的function。 现在,由于存在匿名方法和lambda函数,这种支持可能会变得有用。 如果我在这里遗漏了什么,请有人澄清问题。

大多数情况下,局部变量特定于线程,因此与volatile相关的问题完全没有必要。

当像在你的例子中,它是一个“捕获”变量时,当它被静默地实现为编译器生成的类上的字段时,这会发生变化。 因此理论上它可能是不稳定的,但在大多数情况下,它不值得额外的复杂性。

特别是,像Pulse这样的Monitor (也就是lock )也可以做到这一点,就像任何其他线程结构一样。

线程很棘手,主动循环很少是管理它的最佳方式……


重新编辑… secondThread.Join()将是显而易见的事情 – 但如果您真的想使用单独的令牌,请参阅下文。 这个(比起像ManualResetEvent这样的东西)的优点是它不需要来自操作系统的任何东西 – 它完全在CLI内部处理。

 using System; using System.Threading; static class Program { static void WriteLine(string message) { Console.WriteLine(Thread.CurrentThread.Name + ": " + message); } static void Main() { Thread.CurrentThread.Name = "Main"; object syncLock = new object(); Thread thread = new Thread(DoStuff); thread.Name = "DoStuff"; lock (syncLock) { WriteLine("starting second thread"); thread.Start(syncLock); Monitor.Wait(syncLock); } WriteLine("exiting"); } static void DoStuff(object lockHandle) { WriteLine("entered"); for (int i = 0; i < 10; i++) { Thread.Sleep(500); WriteLine("working..."); } lock (lockHandle) { Monitor.Pulse(lockHandle); } WriteLine("exiting"); } } 

如果要使局部变量表现为易失性,也可以使用Voltile.Write。 如:

 public void MyTest() { bool eventFinished = false; myEventRaiser.OnEvent += delegate { doStuff(); Volatile.Write(ref eventFinished, true); }; myEventRaiser.RaiseEventInSeperateThread() while(!Volatile.Read(eventFinished)) Thread.Sleep(1); Assert.That(stuff); } 

如果在进程退出该局部变量的范围之后直到引发的事件没有完成,会发生什么? 该变量将被释放,您的线程将失败。

明智的方法是附加一个委托函数,该函数向父线程指示子线程已完成。