1. 程式人生 > >c#多執行緒以及Dispatcher.Invoke

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();