2010-11-16 33 views
38
  1. Tại sao tôi nhận được thông báo lỗi này? "WaitAll cho nhiều xử lý trên một chuỗi STA không được hỗ trợ."
  2. Tôi có nên sử dụng [MTAThreadAttribute] không? Cập nhật: Không được làm việc với các ứng dụng WPF!

Lưu ý: Lỗi ở dòng WaitHandle.WaitAll (doneEvents); Tôi đang sử dụng dự án WP2 tiêu chuẩn.WaitAll cho nhiều xử lý trên một chuỗi STA không được hỗ trợ

private void Search() 
{ 
    const int CPUs = 2; 
    var doneEvents = new ManualResetEvent[CPUs]; 

    // Configure and launch threads using ThreadPool: 
    for (int i = 0; i < CPUs; i++) 
    { 
     doneEvents[i] = new ManualResetEvent(false); 
     var f = new Indexer(Paths[i], doneEvents[i]); 
     ThreadPool.QueueUserWorkItem(f.WaitCallBack, i); 
    } 

    // Wait for all threads in pool 
    WaitHandle.WaitAll(doneEvents); 
    Debug.WriteLine("Search completed!"); 
} 

Cập nhật: Các giải pháp sau đây không hoạt động cho các ứng dụng WPF! Không thể thay đổi thuộc tính ứng dụng chính thành MTAThreadAttribute. Điều này sẽ dẫn đến lỗi sau:

Lỗi: "WaitAll cho nhiều xử lý trên chuỗi STA không được hỗ trợ".

+0

Bạn nhận ra rằng bạn ứng dụng sẽ đóng băng hoàn toàn cho đến khi những Indexer được thực hiện? – liggett78

+0

Có! Tôi biết điều đó. Nhưng vì nó không chạy. –

+1

http://stackoverflow.com/questions/3784510/notsupportedexception-on-waithandle-waitall –

Trả lời

17

Điều gì về việc sử dụng Nhiệm vụ để thực hiện luồng cho bạn.

http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx

var task1 = Task.Factory.StartNew(() => DoSomeWork()); 
var task2 = Task.Factory.StartNew(() => DoSomeWork()); 
var task3 = Task.Factory.StartNew(() => DoSomeWork()); 
Task.WaitAll(task1, task2, task3); 
+4

Đó là .NET Framework 4. Vì vậy, tôi phải nâng cấp dự án. Nó có vẻ là một cách tiếp cận tốt hơn suy nghĩ! –

+2

'Task.Run (() => DoSomeWork())' là một lựa chọn tốt hơn – gldraphael

8

Sử dụng một ManualResetEvent và đợi. Đồng thời duy trì biến TaskCount được đặt thành số chuỗi công việc bạn bắt đầu, sử dụng Interlocked.Decrement trong mã chuỗi công việc là hành động cuối cùng của nhân viên và báo hiệu sự kiện nếu bộ đếm đạt đến số không, ví dụ:

// other worker actions... 
if (Interlocked.Decrement(ref taskCount) == 0) 
    doneEvent.Set(); 
+0

Cảm ơn nó có vẻ là giải pháp duy nhất vì WaitAll (..) không hoạt động. –

+0

Đúng, điều đó sẽ hoạt động. Chỉ cần chắc chắn để xử lý các chủ đề chính như thể nó là một mục công việc và khởi tạo 'taskCount = 1' và làm' Decrement' và 'Set' ở cuối vòng lặp' for'. –

6

tôi sẽ cấu trúc lại mã của bạn để sử dụng lớp CountdownEvent để thay thế.

private void Search() 
{ 
    const int CPUs = 2; 
    var done = new CountdownEvent(1); 

    // Configure and launch threads using ThreadPool: 
    for (int i = 0; i < CPUs; i++) 
    { 
     done.AddCount(); 
     var f = new Indexer(Paths[i], doneEvents[i]); 
     ThreadPool.QueueUserWorkItem(
      (state) => 
      { 
      try 
      { 
       f.WaitCallBack(state); 
      } 
      finally 
      { 
       done.Signal(); 
      } 
      }, i); 
    } 

    // Wait for all threads in pool 
    done.Signal(); 
    done.Wait(); 
    Debug.WriteLine("Search completed!"); 
} 
+0

NB: .NET 4 chỉ –

45

Thực ra tôi sử dụng như sau để thay thế WaitHandle.WaitAll (doneEvents);

foreach (var e in doneEvents) 
    e.WaitOne(); 
+1

có bất kỳ nhược điểm nào khi sử dụng phương án này không? – invertigo

+3

Tôi đã không nhìn thấy gì, nhưng tôi khuyên bạn nên sử dụng Tác vụ cho mã mới – Calimero100582

0

sử dụng một cái gì đó như thế này:

foreach (ITask Task in Tasks) 
{ 
    Task.WaitHandle = CompletedEvent; 
    new Thread(Task.Run).Start(); 
} 

int TasksCount = Tasks.Count; 
for (int i = 0; i < TasksCount; i++) 
    CompletedEvent.WaitOne(); 

if (AllCompleted != null) 
    AllCompleted(this, EventArgs.Empty); 
+1

CompletedEvent thuộc loại System.Threading.AutoResetEvent – CSharper

+0

-1 Trong khi trình dọn dẹp, đối với tôi, điều này không đủ khác với http://stackoverflow.com/a/4194938/11635 –

Các vấn đề liên quan