Как предотвратить продвижение вперед, пока не выполнится фоновая задача? - PullRequest
0 голосов
/ 15 октября 2010

У меня есть внешняя библиотека, в которой есть метод, который выполняет долгосрочную задачу в фоновом потоке. Когда это сделано, оно запускает событие Completed в потоке, который запускает метод (обычно в потоке пользовательского интерфейса). Это выглядит так:

public class Foo
{
    public delegate void CompletedEventHandler(object sender, EventArgs e);
    public event CompletedEventHandler Completed;

    public void LongRunningTask()
    {
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        bw.RunWorkerAsync();
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        Thread.Sleep(5000);
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (Completed != null)
            Completed(this, EventArgs.Empty);
    }
}

Код, который вызывает эту библиотеку, выглядит следующим образом:

private void button1_Click(object sender, EventArgs e)
{
    Foo b = new Foo();
    b.Completed += new Foo.CompletedEventHandler(b_Completed);
    b.LongRunningTask();

    Debug.WriteLine("It's all done");    
}

void b_Completed(object sender, EventArgs e)
{
    // do stuff
}

В методе button1_Click, после того, как я вызываю b.LongRunningTask (), событие Completed запускается через 5 секунд в потоке пользовательского интерфейса, я обновляю пользовательский интерфейс и все отлично, так как мне не приходится иметь дело с маршалингом в нужную нить.

Однако теперь мне нужно, чтобы процесс был синхронным (без изменения внешней библиотеки). Другими словами, после того, как я запускаю метод .LongRunningTask, следующее значимое утверждение в этом методе должно сработать после завершения .LongRunningTask.

Я пытался сделать это с EventWaitHandle (например, сделать WaitOne после вызова LongRunningTask, а затем сбросить его в событии Completed, но это просто блокирует все).

Есть ли в .NET Framework метод, позволяющий мне это сделать?

1 Ответ

4 голосов
/ 15 октября 2010

Я пытался сделать это с EventWaitHandle (например, сделать WaitOne после вызова LongRunningTask и затем сбросить его в событии Completed, но это просто блокирует все).

Это именно то, что произойдет, если вы сделаете это синхронным по определению. Вы не можете сделать это синхронно, не блокируя поток пользовательского интерфейса.

Вместо того, чтобы после следующей операции срабатывал «следующий значимый оператор в этом методе», вам нужно либо сделать его блокирующим, либо включить значимый оператор в обратном вызове.

...