使用外部事件中断 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 循环的主要内容,如果未能解决你的问题,请参考以下文章

使用while循环时未触发中断ISR

打破一个while循环并重新启动代码

STM32_按键_外部中断_定时器扫描_循环扫描_FIFO机制

php中在循环外部如何强制结束循环?

如何从while循环内的if条件中断while循环?

在 WHILE 循环中中断关键字与变量