none
多執行緒問題 RRS feed

  • 問題

  • 請問各位
    我的Form上有5各pictureBox(pb1~pb5),有一個執行緒專門在固定時間間隔內
    讓每個pb輪流變色(讀入不同的image圖片,如pb1變黃換pb2變黃,pb1在變回原來的顏色....)
    另外我想要有另一個執行緒能夠一直去掃這5各PB
    當pb變色時能夠回傳目前是哪各pb變色
    控制pb變色的執行緒程式如下:

    //開始執行
    private void btnRun_Click(object sender, EventArgs e)
            {
                if (btnRun.Text.Equals("Run"))
                {
                    btnRun.BackColor = Color.DeepPink;
                    btnRun.Text = "Stop";
                    exitFlag = false;
                    bLoaderSensor = false;
                    //控制變色的執行緒
                    ThreadPool.QueueUserWorkItem(new WaitCallback(StartSend));
                    //偵測變色的執行緒
                    ThreadPool.QueueUserWorkItem(new WaitCallback(LoaderPbSensor));
                }
                else
                {
                    exitFlag = true;
                    bLoaderSensor = true;
                }
            }
           /// <summary>
            /// 開始模擬亮燈
            /// </summary>
            /// <param name="obj"></param>
            private void StartSend(object obj)
            {
                TimerProcess();
            }
            /// <summary>
            ///  模擬特定時間亮燈
            /// </summary>
            private void TimerProcess()
            {
                //每5.5秒變換燈號
                TimeSpan ts = new TimeSpan(0, 0, 0, 5, 500);
                DateTime _currtime = DateTime.Now;
                DateTime _freqtime;
                while (exitFlag == false)
                {
                    _freqtime = DateTime.Now;
                    if (_freqtime.Subtract(_currtime)>=ts)
                    {
                        Loader_Tick();
                        _currtime = DateTime.Now;
                    }
                }
             }
    
            private void Loader_Tick()
            {
             //依照順序改變燈號
                //display畫面燈號
                if (this.InvokeRequired)
                {
                   //run一陣子會跳出,其他地方正在使用物件的例外 
                   this.Invoke(new UpdatePbHandler(LoaderPbControler));//<--                                                                 
                }
                else
                   LoaderPbControler();
            }
    /// <summary> /// 以輪流的方式亮燈 /// </summary> public void LoaderPbControler() { string pbname = "pb"; PictureBox _pbworked = new PictureBox(); for (int i = 1; i <= 5; i++) { switch (pbname + i) { case "pb1": if (pb1.Image.Flags == 77960) { pb1.Image = Properties.Resources.Red; _pbworked = pb2; } break; case "pb2": if (pb2.Image.Flags == 77960) { pb2.Image = Properties.Resources.Red; _pbworked = pb3; } break; case "pb3": if (pb3.Image.Flags == 77960) { pb3.Image = Properties.Resources.Red; _pbworked = pb4; } break; case "pb4": if (pb4.Image.Flags == 77960) { pb4.Image = Properties.Resources.Red; _pbworked = pb5; } break; case "pb5": if (pb5.Image.Flags == 77960) { pb5.Image = Properties.Resources.Red; _pbworked = pb1; } break; default: { _pbworked = pb1; } break; } } _pbworked.Image = Properties.Resources.Yellow; }

    偵測pb變色的執行緒程式如下:

            /// <summary>
            /// 開始感應燈號
             /// </summary>
            /// <param name="obj"></param>
            private void LoaderPbSensor(object obj)
            {
                string _currPb = ""; //目前亮燈的pb
                  string _prevPb = ""; //上一個亮燈的pb
                DateTime _currentTime = DateTime.Now; //實際亮燈時間
                double _waferPassTime = Convert.ToInt32(tbWaferlength.Text) / Convert.ToInt32(tbCVSpeed.Text);
                TimeSpan _timeRange = new TimeSpan(0, 0, 0, 3, 500);
                bool bisfirst = true;
                while (!bLoaderSensor)
                {
                  //偵測燈號
                    _workChannel = LoaderPBSensor();
                    if (bisfirst)
                    {
                        MessageBox.Show(_workChannel);
                    }
                    else 
                    { 
                        //同一pb亮起
                        if (_workChannel.Equals(_tempworkCh)) 
                            {
    //檢查時間間隔,過濾掉間隔太近的 if (DateTime.Now >= _currentTime.Add(_timeRange)) { MessageBox.Show(_workChannel); _currentTime = DateTime.Now; } } else { MessageBox.Show(_workChannel); } } _tempworkCh = _workChannel; bisfirst = false; } Thread.Sleep(1000); } /// <summary> /// 感測哪個燈亮 /// </summary> /// <returns></returns> private string LoaderPBSensor() { string pbname = "pb"; string _workingChannel=""; for (int i = 1; i <= 5; i++) { switch (pbname + i) { case "pb1": if (pb1.Image.Flags == 77960) { _workingChannel = "ch1"; } break; case "pb2": if (pb2.Image.Flags == 77960) { _workingChannel = "ch2"; } break; case "pb3": if (pb3.Image.Flags == 77960) { _workingChannel = "ch3"; } break; case "pb4": if (pb4.Image.Flags == 77960) { _workingChannel = "ch4"; } break; case "pb5": if (pb5.Image.Flags == 77960) { _workingChannel = "ch5"; } break; } } return _workingChannel; }
    在run的時候不是很順,也就是有時候燈號一改變它就能感應到(跳出messagebox)
    但有時候卻會有點Delay不然就是沒偵測到
    而且run一陣子後會出現"其他地方正在使用物件的例外"(在第一段程式)
    我想應該是我的兩個執行緒都有對PB進行動作的關係八
    因為我沒寫過多執行緒的程式,所以對多執行緒不是很了解
    請問各位大大  如果要做到這功能的話 程式該怎麼寫會比較好呢??有哪些地方該修改的 
    請各位不吝指教 謝謝
    2009年5月6日 上午 02:38

解答

  • 你的做法並不適當
    提供給你幾點寫MultiThread的建議

    1.Thread之前能不要存在共用變數就盡量少用,譬如Static,多用區域變數,Thread之間的溝通有很多種方式可以實作,這部分網路上有很多文章可參考.

    2.除了Main Thread(UI Thread)外其他產生的Thread不應該處理UI的問題,也就是不應該在Thread中操作何UI的控制項,應該是使用Event或Callback等方式將需要更改UI的動作註冊到UI Thread中的函式然後用Control.Invoke()方法切換回UI Thread的環境再來操作UI.
    • 已標示為解答 Lolota Lee 2009年5月12日 上午 05:58
    2009年5月7日 上午 09:00

所有回覆

  • Jude13:
          偵測的部份應該改用事件來處理會更好吧,比如你的亮燈是由PictureBox的BackColor屬性所控制的,那就是在PictureBox的BackColorChanged 事件中撰寫處理程序就好.
    2009年5月6日 上午 02:54
    版主
  • 你的做法並不適當
    提供給你幾點寫MultiThread的建議

    1.Thread之前能不要存在共用變數就盡量少用,譬如Static,多用區域變數,Thread之間的溝通有很多種方式可以實作,這部分網路上有很多文章可參考.

    2.除了Main Thread(UI Thread)外其他產生的Thread不應該處理UI的問題,也就是不應該在Thread中操作何UI的控制項,應該是使用Event或Callback等方式將需要更改UI的動作註冊到UI Thread中的函式然後用Control.Invoke()方法切換回UI Thread的環境再來操作UI.
    • 已標示為解答 Lolota Lee 2009年5月12日 上午 05:58
    2009年5月7日 上午 09:00