Как я могу ждать завершения потока, кроме как путем вызова thread.Join ()? - PullRequest
3 голосов
/ 21 июня 2011

Я работаю над проектом, в котором методы вызываются из приложения, которое доступно в библиотеке.

У меня есть код ниже в моем событии нажатия кнопки:

Thread thread = new Thread(new ThreadStart(AddPics));
thread.Priority = ThreadPriority.Highest;
thread.Start();
execute();

Но во время выполнения семпла точка выполнения всегда перемещается к выполнению. Как заставить программу выполнить метод AddPics первым. Я попробовал thread.Join(), и это сработало, но я хочу знать, есть ли другой способ добиться этого.

Ответы [ 2 ]

2 голосов
/ 30 июня 2011

Вы можете использовать Join или AutoResetEvent, чтобы дождаться окончания добавления потока изображений, Но вы не должны использовать ни то, ни другое, как объяснено ниже в ответе.

Вы можете достичь тех же результатов, используя AutoResetEvent в качестве альтернативы Join; он позволяет настроить уведомление о блокировке, поэтому блокируйте перед вызовом метода execute() и продолжайте работу только тогда, когда поток AddPics завершит свою работу:

private AutoResetEvent _finishAddPicsNotifier = new AutoResetEvent(false);

private void OnMyButton_Click(object sender, EventArgs e)
{
    //.....
    new Thread(AddPics)
    {
        Priority = ThreadPriority.Highest,
        IsBackground = true, //will explain later
    }.Start();

    _finishAddPicsNotifier.WaitOne();//this will block until receive a signal to proceed
    execute();//this method will only be called after the AddPics method finished
    /.....
}

private void AddPics()
{
    try{
        //.......
    }
    finally{
        _finishAddPicsNotifier.Set();//when finished adding the pictures, allow the waiting method to proceed
    }
}

Примечание: Установите IsBackground = true, чтобы указать, что поток является фоновым потоком, поэтому он не будет препятствовать завершению приложения. подробнее о фоновой теме здесь .

Проблемы:

  • Поскольку вы используете нажатие кнопки для запуска потока, вы должны добавить некоторый механизм, предотвращающий одновременное многократное нажатие кнопки для многократного выполнения кода.
  • Вы также блокируете поток пользовательского интерфейса при вызове Join() или _finishAddPicsNotifier.WaitOne().

Чтобы исправить все это , хороший дизайн - определить метод OnFinishAddingPictures и вызывать его всякий раз, когда завершается добавление изображений, внутри этого нового вызова метода execute() вы также должны удалить предыдущий execute() звонок от нажатия кнопки:

private readonly object _oneAddPicturesLocker = new object();

private void OnMyButton_Click(object sender, EventArgs e)
{
    //.....
    new Thread(AddPics)
    {
        Priority = ThreadPriority.Highest,
        IsBackground = true,
    }.Start();
}

private void AddPics()
{
    if (Monitor.TryEnter(_oneAddPicturesLocker))
    {
        //we only can proceed if no other AddPics are running.
        try
        {
            //.....

            OnFinishAddingPictures();
        }
        finally
        {
            Monitor.Exit(_oneAddPicturesLocker);
        }
    }
}

private void OnFinishAddingPictures()
{
    execute();
}

Примечание:

  • С помощью этого механизма мы избавляемся от блокировки.
  • Мы уверены, что один и только один вызов AddPics выполняется в данный момент.
  • Всегда не забывайте проверять InvokeRequired и использовать control.Invoke(/*..*/) при каждом обращении к форме или методам управления и свойствам из потока, который не является потоком пользовательского интерфейса .
0 голосов
/ 01 июля 2011

Я предполагаю, что ваша основная задача - иметь отзывчивый пользовательский интерфейс во время работы потока с AddPics?Если это так, то вы можете использовать эту конструкцию для WinForms:

while (thread.IsAlive)
    System.Windows.Forms.Application.DoEvents();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...