c#多執行緒以及Dispatcher.Invoke
主執行緒
private void Stabilitybutton_Click(object sender, RoutedEventArgs e) { for (int Nr = 0; Nr <= 10; Nr++) { byte[] msg = new byte[] { 0x00, 0x00, 0x01, 0x01, 0x00, 0xC0, 0x01, 0x16, 0x1B, 0xFF, 0xFF, 0xFF }; msg[4] = (byte)Nr; sendMsg(msg); } }
private void sendMsg(byte[] msgBody, bool isResent = false) { byte[] msg = null; if (isResent) { msg = msgBody; resendCount++; } else { resendCount = 0; msg = msgBody; } if (resendCount > 2) { LogUtil.Logger.Error("【傳送超時且超出最大發送次數】"); } else { currentCmd = msg; if (ConnectServer()) { //tcpClient.Send(msg, msg.Length, SocketFlags.None); //Thread.Sleep(1000); this.Dispatcher.Invoke(new Action(() => { tcpClient.Send(msg, msg.Length, SocketFlags.None); })); LogUtil.Logger.Info("【send資料】" + ScaleConvertor.HexBytesToString(msg)); // tcpClient.ReceiveTimeout = 5000; this.Dispatcher.Invoke(new Action(() => { SendMessageText.AppendText(ReadMessage.Parser.readMessage(msg) + "\n"); })); } } }
這樣的結果是隻有等待for迴圈結束後才執行其他語句,如圖:
造成了阻塞
預期結果:
解決方案:
在新的執行緒中執行傳送部分語句,即for迴圈和傳送採用多執行緒分隔。
失敗方案:
由於對Invoke的理解有誤,剛開始試圖呼叫Dispatcher.Invoke來進行一個新的執行緒
this.Dispatcher.Invoke(new Action(() => { tcpClient.Send(msg, msg.Length, SocketFlags.None); }));
this.Dispatcher.Invoke(new Action(() => { SendMessageText.AppendText(ReadMessage.Parser.readMessage(msg) + "\n"); }));
在此重新學習一下Dispatcher.Invoke的定義:
從主 UI 執行緒派生的後臺執行緒不能更新的內容 Button UI 執行緒上建立。 為了使後臺執行緒訪問的內容屬性的 Button, ,後臺執行緒必須將工作委託給 Dispatcher 與 UI 執行緒關聯。
即 窗體控制元件是由主執行緒A執行的,因此在多執行緒中試圖更改控制元件的內容比如覆蓋或追加textbox的內容,是無法在分執行緒中執行的
//虛擬碼
ClientSendThread = new Thread(Send);
private void Send()
{
messagebox.Show("hello");
}
這樣是無法執行的,因為messabox是由UI介面執行緒控制的,因此採用 this.Dispatcher.Invoke(new Action(() => {}));呼叫messagebox
回到主題
正確的解決方案:
ClientSendThread = new Thread(sendMsg);
ClientSendThread.IsBackground = true;
ClientSendThread.Start();