Я хотел бы выполнить код альтернативно, таким образом, я мог остановить выполнение в любой момент. Действительно ли этот код безопасен?
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
цикл.
Рекомендую ознакомиться с этой записью в блоге о реализации 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()) ;
}
}
" ... это будет приложение с графическим интерфейсом ... "
Тогда вы, вероятно, не хотите и не будете иметь последовательного кода, как указано выше в Main ()
.
Т.е. основной поток графического интерфейса пользователя не будет выполнять последовательный код, как указано выше, но обычно будет бездействовать, перерисовывать и т. д. или обрабатывать нажатие кнопки Продолжить
.
В этом обработчике событий вам лучше использовать Auto | ManualResetEvent
, чтобы сигнализировать рабочему о продолжении.
В воркере просто дождитесь события.