Действительно ли это - безопасный способ выполнить потоки альтернативно?

Я хотел бы выполнить код альтернативно, таким образом, я мог остановить выполнение в любой момент. Действительно ли этот код безопасен?

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 цикл.

1
задан prostynick 28 June 2010 в 20:52
поделиться

2 ответа

Рекомендую ознакомиться с этой записью в блоге о реализации fibers.

Код (На случай падения сайта.)

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()) ;
  }
}
1
ответ дан 2 September 2019 в 23:26
поделиться

" ... это будет приложение с графическим интерфейсом ... "

Тогда вы, вероятно, не хотите и не будете иметь последовательного кода, как указано выше в Main () .

Т.е. основной поток графического интерфейса пользователя не будет выполнять последовательный код, как указано выше, но обычно будет бездействовать, перерисовывать и т. д. или обрабатывать нажатие кнопки Продолжить .
В этом обработчике событий вам лучше использовать Auto | ManualResetEvent , чтобы сигнализировать рабочему о продолжении.
В воркере просто дождитесь события.

1
ответ дан 2 September 2019 в 23:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: