代码之家  ›  专栏  ›  技术社区  ›  Patrick Huizinga

为什么局部变量在c中不能是可变的?

  •  17
  • Patrick Huizinga  · 技术社区  · 15 年前
    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曾经是局部变量这一事实的优化。

    4 回复  |  直到 7 年前
        1
  •  12
  •   MondKin    7 年前

    存在线程处理原语, 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之前没有使用过这种功能。现在,随着匿名方法和lambda函数的存在,这种支持可能会变得有用。如果我遗漏了什么,请有人澄清。

        2
  •  10
  •   Marc Gravell    15 年前

    场景中,局部变量是特定于线程的,因此与 volatile 完全没有必要。

    当它是一个“捕获的”变量时,这种情况就会发生变化,就像在您的示例中一样,当它在编译器生成的类上被静默地实现为一个字段时。所以从理论上讲 能够 不稳定,但在大多数情况下,它不值得额外的复杂性。

    尤其是像 Monitor (阿卡 lock Pulse ETC也可以做到这一点,任何其他线程构造都可以做到这一点。

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


    重新编辑… 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");
        }
    }
    
        3
  •  5
  •   Frederik Gottlieb    7 年前

    如果您想使局部变量表现为易失性,也可以使用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);
    }
    
        4
  •  1
  •   Lazarus    15 年前

    如果引发的事件直到进程退出该局部变量的作用域后才完成,会发生什么?变量将被释放,线程将失败。

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