2014-01-07 5 views
1

У меня есть приложение на основе форм. Пользовательский интерфейс обрабатывается потоком. Из потока пользовательского интерфейса я создаю 3 потока для выполнения некоторой обработки.Синхронизация потоков в C#

Thread t1 = new Thread(() => performprocessing()); 
Thread t2 = new Thread(() => performprocessing()); 
Thread t3 = new Thread(() => performprocessing()); 

Теперь я хочу, чтобы выполнить инструкцию в потоке пользовательского интерфейса после того, как все 3 нити заканчивают execution.So, я сделал следующее:

do 
{ 

} while (t1.IsAlive || t2.IsAlive || t3.IsAlive); 
/*--execute statement---*/ 

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

Я читал о событиях ручной и автоматической перезагрузки, но я не уверен, как их использовать в этом случае. Прошу вас посоветуйте.

ответ

5

Пробуйте использовать Barrier.

Вам необходимо передать экземпляр Barrier в вашу нить, а затем использовать Barrier.SignalAndWait() из темы. Укажите количество сигналов, которые необходимо выполнить в конструкторе Barrier.

Как только все сигналы будут получены, потоки, которые ждут, перестанут блокироваться.

0

Используйте рабочий поток работника, и вы можете сохранить ui отзывчивым и отправить прогресс.

void Form1_Load(object sender, EventArgs e) 
     { 
      BackgroundWorker b1 = new BackgroundWorker(); 
      BackgroundWorker b2 = new BackgroundWorker(); 
      BackgroundWorker b3 = new BackgroundWorker(); 
      b1.RunWorkerCompleted += b1_RunWorkerCompleted; 
      b2.RunWorkerCompleted += b2_RunWorkerCompleted; 
      b3.RunWorkerCompleted += b3_RunWorkerCompleted; 
     } 

     void b1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
     } 

     void b2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
     } 

     void b3_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
     } 
+0

Пожалуйста, не используйте это. Ваш 'if (workerCompleted == 3)' не является потокобезопасным. Там может быть возможность - до отношений здесь. Помните, что OP не дал контекста того, как будут использоваться потоки, только что он имеет поток пользовательского интерфейса и 3 отдельных рабочих потока. –

+0

Ответ обновлен, чтобы удалить проблему с потоками и сделать ее более общей, спасибо @ dan-pantry – Marko

2

Нерест новых потоков - это плохая практика, вместо этого используйте пул потоков.

{ 
    var t1 = Task.Run(() => doSomething1()); 
    var t2 = Task.Run(() => doSomething2()); 
    var t3 = Task.Run(() => doSomething3()); 

    Task.WhenAll(t1, t2, t3).ContinueWith(t => doSomething4()); 
} 

Более чистый подход для .NET 4.5 заключается в использовании async/await.

async void Form1_Load(object sender, EventArgs e) 
{ 
    var t1 = Task.Run(() => doSomething1()); 
    var t2 = Task.Run(() => doSomething2()); 
    var t3 = Task.Run(() => doSomething3()); 

    await Task.WhenAll(t1, t2, t3); 
    doSomething4(); 
} 

.NET 4.0 не определяет Task.Run() и Task.WhenAll(), используйте вместо Task.Factory.

{ 
    var t1 = Task.Factory.StartNew(() => doSomething1()); 
    var t2 = Task.Factory.StartNew(() => doSomething2()); 
    var t3 = Task.Factory.StartNew(() => doSomething3()); 

    Task.Factory.ContinueWhenAll(new[] { t1, t2, t3}, tasks => doSomething4()); 
} 
+0

.Net 4.0 не имеет метода Task.Run(). Я должен сделать это с помощью методов Task.Factory.StartNew() и Task.Factory.ContinueWhenAll(). – Kaushik

+0

'Task.Start()'? https://gist.github.com/DanPantry/8296168 выдержка из моего текущего проекта, в котором используется задача в 4.0 –

+0

@Kaushik Добавлены комментарии к ответу, охватывающим .NET 4.0. –

-1

Если по каким-либо причинам вы не хотите использовать Task как уже упоминалось solmaks, то вы можете использовать метод Join(), который будет блокировать, пока поток не завершен.

Thread t1 = new Thread(() => performprocessing()); 
Thread t2 = new Thread(() => performprocessing()); 
Thread t3 = new Thread(() => performprocessing()); 

t1.Join(); 
t2.Join(); 
t3.Join(); 

Я бы не рекомендовал использовать это в потоке пользовательского интерфейса, так как это могло бы сделать ваше приложение неприемлемым.

+0

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

Смежные вопросы