使用外部事件中断 while 循环
Posted
技术标签:
【中文标题】使用外部事件中断 while 循环【英文标题】:Break a while loop using external event 【发布时间】:2012-09-20 14:50:43 【问题描述】:我在 Windows 服务中有一个 while 循环,它运行了 x 次,并在从某个文件中读取它们后发起 x 个电话呼叫。现在,如果我想创建一个用户界面,它提供了停止电话呼叫的选项,即在 while 循环完成之前就中断它。我该怎么办?
假设我有一个函数。
DialCalls(x)
for(int i= 0 ; i<x ; i++)
// Initiate call
可以有 2,3 个 DialCalls 函数同时在不同的线程中运行,因为我也在应用程序中进行了线程化。所以基本上什么是打破网页循环的最佳方法。
【问题讨论】:
对于建议volatile
的人:blogs.msdn.com/b/ericlippert/archive/2011/06/16/…
【参考方案1】:
使用task 取消(.net 4 中的新功能):
[Fact]
public void StartAndCancel()
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
var tasks = Enumerable.Repeat(0, 2)
.Select(i => Task.Run(() => Dial(token), token))
.ToArray(); // start dialing on two threads
Thread.Sleep(200); // give the tasks time to start
cancellationTokenSource.Cancel();
Assert.Throws<AggregateException>(() => Task.WaitAll(tasks));
Assert.True(tasks.All(t => t.Status == TaskStatus.Canceled));
public void Dial(CancellationToken token)
while (true)
token.ThrowIfCancellationRequested();
Console.WriteLine("Called from thread 0", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50);
http://blogs.msdn.com/b/csharpfaq/archive/2010/07/19/parallel-programming-task-cancellation.aspx 该任务会吞下异常,因此需要进行一些清理,例如 IDisposable? About task exceptions
【讨论】:
这是一个很好的答案(所以 +1),但您可以通过包含文章中的一些相关 sn-ps 来改进它。【参考方案2】:您可以在循环中编写 if 语句,以轮询外部事件的状态。
例如,你可以有一个标志:
bool break_out = false;
在您的外部事件中,您将 break_out 标志设置为 true:
break_out = true;
现在在您的循环中,您可以:
DialCalls(x)
for(int i= 0 ; i<x ; i++)
// Initiate call
if (break_out)
break;
【讨论】:
【参考方案3】:创建一个支持取消的事件:
public event EventHandler<CancelEventArgs> Call;
如果订阅者存在并取消,请勿调用:
while (true)
var e = new System.ComponentModel.CancelEventArgs();
if (Call != null)
Call(this, e);
if (!e.Cancel)
// Initiate call
else
break;
【讨论】:
【参考方案4】:通过使用一个告诉何时中断的变量。
private bool _cancel;
void DialCalls(...)
for (int i=0; i<x; i++)
...
if (_cancel) break;
....
private void SomeEventHandler(object sender, EventArgs e)
_cancel = true;
或
for (int i=0; i<x && !_cancel; i++)
【讨论】:
【参考方案5】:有一个易变的全局变量
public static volatile bool stop;
stop=False;
DialCalls(x)
for(int i= 0 ; i<x && !stop ; i++)
// Initiate call
On Button Click => stop =True;
【讨论】:
【参考方案6】:在服务上实现一个端点,该端点接受一个切换全局/静态布尔(或其他)变量的消息,并让DialCalls
内的循环在每次迭代开始时检查所述变量。它不会打断当前正在进行的任何电话通话,但我敢打赌,您不希望该服务在通话过程中挂断,只是不要继续进行下一个通话。这也会中断所有线程;只需确保变量本身是线程安全的(例如,使用 volatile
关键字)。
【讨论】:
【参考方案7】:while (!_shouldStop) /* work in progress */
并且在应该在同一个工作类上的Stop()
方法中,bool变量必须设置为true。
另外,如果有任何服务员(如AutoResetEvent
),他们必须是.Set();
。
【讨论】:
以上是关于使用外部事件中断 while 循环的主要内容,如果未能解决你的问题,请参考以下文章