我想交替运行代码,所以我可以随时停止执行。这段代码安全吗?
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
循环更复杂。
答案 0 :(得分:1)
“......这将是GUI应用......”
然后你可能不希望也不会在Main()
中拥有上述顺序代码。
即。主GUI线程不会像上面那样执行串行代码,但通常是空闲,重新绘制等,或处理Continue
按钮点击。
在该事件处理程序中,您最好使用Auto|ManualResetEvent
来指示工作人员继续进行
在工人中,等待活动。
答案 1 :(得分:1)
我建议您查看有关实施光纤的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 :(得分:0)
我建议任何时候考虑使用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
。因此,如果未跳过Wait
,则PulseAll
可以保证唤醒它。请注意,如果Wait
自发地表现为接收到一个脉冲,代码就可以正常工作 - 它只会旋转,观察turn
没有为当前线程设置,然后返回等待