2012-03-28 105 views
6

好的..這將是漫長的,但我需要先解釋一些背景。多線程和串口

我的這部分軟件是分類順着傳送帶上的物品。 我使用Modbus作爲傳送帶。 Modbus將在特定時間打開門,讓物品通過門。項目將根據體重通過某些門。

我監測的傳感器,以確定何時產品的規模。當傳感器被阻塞時,物品被稱重並被髮送到適當的門。定時器設置爲打開/關閉門。

我的代碼會爲this..the問題的工作是,它不會爲多個項目工作。我的意思是,當門打開時,傳感器在門關閉之前不被監控。因此,當物品A在通往大門的路上時,物品B在阻塞傳感器時不會在秤上稱重。一次最多可以有8個項目在線上。這裏是我現在運行的代碼:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
} 

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if sensor is blocked 
    if (sensorstatus == 0) 
    { 
     //the timers just start the thread 
     scaleTimer.Start(); 
    } 
    else 
    { 
     sensorTimer.Start(); 
    } 
} 

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     ReadScale(); 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     SetOpenDelay(); 
     SetDuration(); 
    } 
    } 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if gate = 0, this means the weight of meat on scale 
    //is not in any weight range. Meat runs off the end. 
    if (gate == 0) 
    { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
     sensorTimer.Start(); 
    } 
    else 
    { 
     //open gate 
     //then close gate 
    } 
    } 

這段代碼工作正常,我只需要能夠考慮線上的多個項目。 任何建議????

我也試過如下:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
}  

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    sensorTimer.Start(); 
} 

    private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     //sensor blocked 
     if (sensorstatus == 0) 
     { 
      ReadScale(); 
      //SaveWeight(); 
      prevgate = gate; 
      gate = DetermineGate(); 
      SetOpenDelay(); 
      SetDuration(); 

      //if gate = 0, this means the weight of meat on scale 
      //is not in any weight range. Meat runs off the end. 
      if (gate == 0) 
      { 
      txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
      } 
      else 
      { 
      //open gate 
      //close gate 
      } 
    } 
} 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    scaleTimer.Start(); 
} 

當我做這個,我開始兩個線程按下啓動按鈕時。我得到各種異常,程序最終拋出SEHException和崩潰。我得到的其他錯誤說「串口已經打開」或「I/O錯誤」。

+0

這樣的問題DetermineGate(),SetOpenDelay()和SetDuration在規模線程塊()?我還沒完全理解你的代碼。它看起來仍然是非常程序化的,即使你正在使用線程 - 看起來像線程總是在等待着彼此。這是發生了什麼? – 2012-03-28 20:31:27

+0

僅供參考,這裏是多線程在C#中有很大的聯繫:http://www.yoda.arachsys.com/csharp/threads/index.shtml – 2012-03-28 20:33:13

+0

這是我第一次多線程。我需要它在我的GUI不鎖定的地方。我不確定你的意思是「線程擴展塊」線程正在彼此等待。但是當我試圖修復它時,我只是遇到了一堆錯誤(請參閱我的編輯)。我需要這個軟件才能運行傳送帶。它應該以每3秒1次的速度計算傳感器傳遞的物品。所以所有的大門都應該在物品到達門口時打開/關閉。我知道這聽起來令人困惑。你明白我想要完成什麼嗎?感謝您的鏈接 – CSharpDev 2012-03-28 20:37:57

回答

1

我建議你最好的選擇可能是創建一個專用的線程坐下每個串口上。這種方法既不需要也不禁止端口處理方面的任何相似性,將避免端口之間操作的任何干擾,並且將在合理範圍內可擴展(對於32個端口中的每個端口使用線程將是好的;使用每1,000個線程會很糟糕)。儘管應該避免創建線程,這些線程只需要很短的時間就可以退出,或者創建非常多的線程,但是爲每個串行端口使用專用線程將確保數據進入時會有線程準備好處理它。

+0

我試過這個。我有一個專用於傳感器的線程和一個專用於該傳感器的線程。如果傳感器被堵塞(秤上有東西),秤螺紋只抓住重量。然後,一旦我體重增加,我會產生一條線來處理大門。但我永遠不會讓它進入該線程,因爲我在閱讀比例和傳感器時遇到了錯誤。這兩個線程不會一起工作。他們在不同的COM端口和一切,所以我不知道怎麼回事 – CSharpDev 2012-03-28 20:45:06

+0

我的建議是在啓動時啓動所有線程,並讓它們運行。啓動線程很昂貴。讓線程連續不斷地執行代碼是非常昂貴的。然而,讓一條線程等待I/O,會比較便宜。不是那麼便宜,一個人應該有數百人無緣無故地跑,但便宜到八人通常沒什麼大不了的。 – supercat 2012-03-29 14:21:42

1

我注意到你的線程的DoWork方法沒有任何循環。那將是一個開始的好地方。工作線程應該是一個循環,直到CancellationPending設置爲true纔會返回。它們不會因爲它在一個線程中而自行循環 - 線程會一直運行直到完成,然後退出。

編輯補充:你似乎什麼是失蹤的是,你需要分割,監控規模的代碼,並打開和關閉門的代碼。要做到這一點的一種方法是有一個無限循環來監視比例,當它檢測到某個東西時,它會啓動一個處理打開和關閉門的新線程。

+0

感謝查理(和湯姆)爲upvote。根據我的理解,我認爲這個循環是由一個線程調用另一個線程「引發」的。 – AlexDev 2012-03-28 20:37:09

+0

Gotcha,但然後OP仍在使用過程代碼 - 一種方法不會運行,直到其他方法調用它。線程化的思想是讓一個代碼獨立於另一個運行,當它發現一些冗長的代碼時(比如打開和關閉門),它會將這些工作轉化爲新的線程。或者我錯過了什麼? – 2012-03-28 20:40:20

+0

我循環RunWorkerCompleted方法中的線程。它啓動一個定時器,它在滴答後調用線程。 – CSharpDev 2012-03-28 20:48:17

2

我認爲你需要這樣的東西。不知道是否需要的鎖,但我加入他們的安全,因爲你得到的錯誤

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int sensor = 1; 
    while(!SensorThread.CancellationPending == true) 
    { 
     int newSensor; 
     lock(this) 
     { 
      newSensor = ReadSensor(); 
     } 

     //sensor state changed 
     if(newSensor != sensor) 
     { 
      //sensor was 1 and changed to 0 
      if(newSensor==0) 
      { 
       scaleTimer.Start(); 
      } 
      sensor = newSensor; 
     } 
     Thread.Sleep(1); 
    } 
    e.Cancel = true; 
}  

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //sensor blocked 
    //if (sensorstatus == 0) 
    { 
     lock(this) 
     { 
      ReadScale(); 
     } 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     lock(this) 
     { 
      SetOpenDelay(); 
      SetDuration(); 
     } 

     //if gate = 0, this means the weight of meat on scale 
     //is not in any weight range. Meat runs off the end. 
     if (gate == 0) 
     { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                      "lbs is out of range"}); 
     } 
     else 
     { 
     lock(this) 
     { 
     //open gate 
     } 
     lock(this) 
     { 
     //close gate 
     } 
     } 
    } 
+0

那麼newSensor應該如何開始真正的價值?你能詳細解釋一下你在這裏做什麼嗎? – CSharpDev 2012-03-28 22:03:56

+0

修復了newSensor初始化。正如其他人所建議的那樣,這個想法是,傳感器線程循環檢查傳感器,當它檢測到狀態發生變化時,它會觸發標尺線程。 – AlexDev 2012-03-29 11:06:28

+0

我會給這個鏡頭看看會發生什麼。謝謝! – CSharpDev 2012-03-29 12:09:32