代码之家  ›  专栏  ›  技术社区  ›  prostynick

这是一种安全的交替执行线程的方法吗?

  •  1
  • prostynick  · 技术社区  · 16 年前

    我希望交替运行代码,以便随时停止执行。这个密码安全吗?

    static class Program
    {
        static void Main()
        {
            var foo = new Foo();
            //wait for interaction (this will be GUI app, so eg. btnNext_click)
            foo.Continue();
            //wait again etc.
            foo.Continue();
            foo.Continue();
            foo.Continue();
            foo.Continue();
            foo.Continue();
        }
    }
    
    class Foo
    {
        public Foo()
        {
            new Thread(Run).Start();
        }
    
        private void Run()
        {
            Break();
            OnRun();
        }
    
        protected virtual void OnRun()
        {
            for (var i = 0; i < 5; i++)
            {
                Console.WriteLine(i);
                Break();
            }
            //do something else and break;
        }
    
        private void Break()
        {
            lock (this)
            {
                Monitor.Pulse(this);
                Monitor.Wait(this);
            }
        }
    
        public void Continue()
        {
            lock (this)
            {
                Monitor.Pulse(this);
                Monitor.Wait(this);
            }
        }
    }
    

    当然,我知道,现在应用程序永远不会结束,但这不是重点。

    我需要这个,因为我想用某种算法来表示步骤,并描述在特定时刻发生的事情,并且使一个线程中的所有内容都会导致许多复杂的情况,即使在代码中使用少量的循环。例如,这些行:

    for (var i = 0; i < 5; i++)
    {
        Console.WriteLine(i);
        Break();
    }
    

    然后应替换为:

    if (this.i < 5)
    {
        Console.WriteLine(i++);
    }
    

    这只是我想展示的一个小例子。代码将比虚拟代码更复杂 for 循环。

    3 回复  |  直到 13 年前
        1
  •  1
  •   ChaosPandion    16 年前

    blog post

    public class Fiber
    {
        private readonly Stack<IEnumerator> stackFrame = new Stack<IEnumerator>();
        private IEnumerator currentRoutine;
    
        public Fiber(IEnumerator entryPoint)
        {
            this.currentRoutine = entryPoint;
        }
    
        public bool Step()
        {
            if (currentRoutine.MoveNext())
            {
                var subRoutine = currentRoutine.Current
                               as IEnumerator;
                if (subRoutine != null)
                {
                    stackFrame.Push(currentRoutine);
                    currentRoutine = subRoutine;
                }
            }
            else if (stackFrame.Count > 0)
            {
                currentRoutine = stackFrame.Pop();
            }
            else
            {
              OnFiberTerminated(
                  new FiberTerminatedEventArgs(
                      currentRoutine.Current
                  )
              );
              return false;
          }
    
          return true;
        }
    
        public event EventHandler<FiberTerminatedEventArgs> FiberTerminated;
    
        private void OnFiberTerminated(FiberTerminatedEventArgs e)
        {
            var handler = FiberTerminated;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
    
    public class FiberTerminatedEventArgs : EventArgs
    {
      private readonly object result;
    
      public FiberTerminatedEventArgs(object result)
      {
          this.result = result;
      }
    
      public object Result
      {
          get { return this.result; }
      }
    }   
    
    class FiberTest
    {
      private static IEnumerator Recurse(int n)
      {
          Console.WriteLine(n);
          yield return n;
          if (n > 0)
          {
              yield return Recurse(n - 1);
          }
      }
    
      static void Main(string[] args)
      {
          var fiber = new Fiber(Recurse(5));
          while (fiber.Step()) ;
      }
    }
    
        2
  •  1
  •   Andras Vass    16 年前

    Main()

    Continue
    Auto|ManualResetEvent

        3
  •  0
  •   supercat    13 年前

    Monitor.Wait() Wait

    lock(monitorObj)
    {
      while(notYetReady)
        Monitor.Wait(monitorObj);
    }
    

    lock(monitorObj)
    {
      turn = [[identifier for this "thread"]];
      Monitor.PulseAll(monitorObj);
      while(turn != [[identifier for this "thread"]])
        Monitor.Wait(monitorObj);
    }
    

    turn Monitor.Wait 等待 PulseAll 一定会唤醒它。注意,如果 等待 自发地像接收到一个脉冲一样——它只是旋转,观察 没有为当前线程设置,请返回等待状态。

    推荐文章