Прервать цикл while с помощью внешнего события

У меня есть цикл while в службе windows, которая работает в течение некоторого x раз и инициирует X телефонные звонки после их чтения из некоторого файла . Теперь, если я хочу сделать пользовательский интерфейс, который дает возможность остановить телефонные звонки, т. е. разорвать цикл while еще до его завершения. Как мне это сделать ?

допустим у меня есть функция .

DialCalls(x)
{
  for(int i= 0 ; i<x ; i++)
  {
    // Initiate call
  }
}

могут быть функции 2,3 DialCalls, работающие одновременно в разных потоках, как я сделал threading в применение также . Так что в основном, что лучший способ разорвать цикл с веб-страницы может быть.

7 ответов


С помощью задание отмена (новое в .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? об исключениях задачи


вы можете написать 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;
    }
  }
}

создайте событие, поддерживающее отмену:

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;
    }
}

while (!_shouldStop) { /* work in progress */ }

и Stop() метод, который должен быть в том же рабочем классе переменная bool должна быть установлена как true.

кроме того, если есть официанты (например,AutoResetEvent) они должны быть .Set();.


С помощью переменной, указывающей, когда сломать.

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++)

имеют глобальную переменную, которая является изменчивой

public static volatile bool stop;    
stop=False;

DialCalls(x)
{
  for(int i= 0 ; i<x && !stop ; i++)
  {
    // Initiate call
  }
}

On Button Click => stop =True;

реализуйте конечную точку в службе, которая принимает сообщение, которое переключает глобальную / статическую логическую (или какую-либо другую) переменную, и имеет цикл внутри DialCalls проверить переменную в начале каждой итерации. Он не будет прерывать телефонные звонки в настоящее время, но я держу пари, что вы не хотите, чтобы служба повесила трубку в середине звонка, просто не переходите к следующему. Это также прервало бы все потоки; просто убедитесь, что сама переменная является потокобезопасной (например, используйте volatile ключевое слово).