從上一篇可知ThreadPool的基本設定了,不過接下來又遇上新的問題。
- 如何確認所有執行緒完成?
- 將主控台專案改為WinForm專案使用ThreadPool...
首先,先說明如何確認所有執行緒完成工作?
在此我使用者WaitHandle.WaitAll()來確認。
依照官網的說明,必須將doneEvent = new ManualResetEvent(false)帶入ThreadPool,最終使用doneEvent陣列帶入WaitHandle.WaitAll()即可。
二話不說,先上程式碼。
- internal class Program
- {
- static void Main(string[] args)
- {
- const int FibonacciCalculations = 10;
- firtstTest(FibonacciCalculations);
- }
- private static void ThreadPoolCallbackV1(object obj)
- {
- if(obj == null) return;
- ManualResetEvent doneEvent = (ManualResetEvent)obj;
- Console.WriteLine(nameof(ThreadPoolCallbackV1));
- doneEvent.Set();
- }
- private static void firtstTest(int theadCount)
- {
- ThreadPool.SetMinThreads(2, 2);
- ThreadPool.SetMaxThreads(3, 3);
- ManualResetEvent[] doneEvents = new ManualResetEvent[theadCount];
- for(var i = 0; i < theadCount; i++)
- {
- doneEvents[i] = new ManualResetEvent(false);
- Console.WriteLine($"{nameof(firtstTest)} 第 {i} 次執行...");
- ThreadPool.QueueUserWorkItem(ThreadPoolCallbackV1, doneEvents[i]);
- }
- WaitHandle.WaitAll(doneEvents);
- Console.WriteLine("All calculations are complete.");
- }
- }
是的,這個是主控台的程式碼,當所有執行緒完成後,才會印出最後一個句子。
接下來的問題,就是要把這段程式碼改道WomForm的專案了...
最剛開始,我想...在主控台都測通過了,沒有問題。於是,隨便開了個空的Form表單,就把程式碼貼過去了。
結果? 當然是失敗了...
我花了至少三天才搞定它,雖然解法非常簡單...
二話不說,先上程式碼。
Program.cs
- internal static class Program
- {
- ///
/// The main entry point for the application. /// - //[STAThread] 將STAThread改為MTAThread,WaitHandle.WaitAll不支援STAThread,改為MTAThread就能夠執行...
- [MTAThread]
- static void Main()
- {
- // To customize application configuration such as set high DPI settings or default font,
- // see https://aka.ms/applicationconfiguration.
- ApplicationConfiguration.Initialize();
- Application.Run(new Form1());
- }
- }
Form1.cs
- private string _content = string.Empth;
- public partial class Form1 : Form
- {
- public TpcGrpcStressTest()
- {
- InitializeComponent();
- }
- private static void ThreadPoolCallbackV1(object obj)
- {
- if(obj == null) return;
- ManualResetEvent doneEvent = (ManualResetEvent)obj;
- _content += nameof(ThreadPoolCallbackV1) + Environment.NewLine;
- doneEvent.Set();
- }
- private static void firtstTest(int theadCount)
- {
- ThreadPool.SetMinThreads(2, 2);
- ThreadPool.SetMaxThreads(3, 3);
- ManualResetEvent[] doneEvents = new ManualResetEvent[theadCount];
- for(var i = 0; i < theadCount; i++)
- {
- doneEvents[i] = new ManualResetEvent(false);
- _content += $"{nameof(firtstTest)} 第 {i} 次執行..." + Environment.NewLine;
- ThreadPool.QueueUserWorkItem(ThreadPoolCallbackV1, doneEvents[i]);
- }
- WaitHandle.WaitAll(doneEvents);
- }
- private void SubmitBtn_Click(object sender, EventArgs e)
- {
- firtstTest(10);
- TextBox1.Text = _content + "All calculations are complete.";
- }
- }
答案超簡單,但困擾我許久,特別記錄下來,免得下次又發生。
參考網址: AutoResetEvent.WaitAll 等到人生三大事,然后大笑开心。
本以為到此為止,但是當我測試超過100筆執行緒時,又一個問題出現了...
System.NotSupportedException: 'The number of WaitHandles must be less than or equal to 64.'
再去查了資訊,才發現原來超過64個執行緒使用WaitHandle.WaitAll會錯誤...
實際找到解法後,說明不需要使用WaitHandle.WaitAll來檢查程序是否執行完成,那麼二話不說,修改程式碼...
Program.cs
- internal static class Program
- {
- ///
/// The main entry point for the application. /// - [STAThread]
- static void Main()
- {
- // To customize application configuration such as set high DPI settings or default font,
- // see https://aka.ms/applicationconfiguration.
- ApplicationConfiguration.Initialize();
- Application.Run(new Form1());
- }
- }
Form1.cs
- public partial class Form1 : Form
- {
- private string _content = string.Empth;
- private static int _numerOfThreadsNotYetCompleted = 0;
- private static ManualResetEvent _doneEvent = new ManualResetEvent(false);
- public TpcGrpcStressTest()
- {
- InitializeComponent();
- }
- private static void ThreadPoolCallbackV1(object obj)
- {
- if(obj == null) return;
- try
- {
- ManualResetEvent doneEvent = (ManualResetEvent)obj;
- _content += $"{nameof(ThreadPoolCallbackV1)} 第 {(int)i} 次執行...") + Environment.NewLine;
- doneEvent.Set();
- }
- finally
- {
- if (Interlocked.Decrement(ref _numerOfThreadsNotYetCompleted) == 0)
- _doneEvent.Set();
- }
- }
- private static void firtstTest(int theadCount)
- {
- ThreadPool.SetMinThreads(2, 2);
- ThreadPool.SetMaxThreads(3, 3);
- for(var i = 0; i < theadCount; i++)
- {
- _content += nameof(firtstTest) + Environment.NewLine;
- ThreadPool.QueueUserWorkItem(ThreadPoolCallbackV1, (object)i);
- }
- _doneEvent.WaitOne();
- }
- private void SubmitBtn_Click(object sender, EventArgs e)
- {
- _numerOfThreadsNotYetCompleted = 100;
- firtstTest(100);
- TextBox1.Text = _content + "All calculations are complete.";
- }
- }
參考網址: Solved: “The number of WaitHandles must be less than or equal to 64″
沒有留言:
張貼留言