2010-05-11 116 views
0

我的C#應用​​程序是這樣的,後臺工作人員正在用來等待一些傳輸數據的確認。這裏是一些僞代碼演示我想要做的事:使用BackgroundWorker在C#中併發線程

UI_thread 
{ 
    TransmitData() 
    { 
     // load data for tx 
     // fire off TX background worker 
    } 

    RxSerialData() 
    { 
     // if received data is ack, set ack received flag 
    } 
} 

TX_thread 
{ 
    // transmit data 
    // set ack wait timeout 
    // fire off ACK background worker 
    // wait for ACK background worker to complete 
    // evaluate status of ACK background worker as completed, failed, etc. 
} 

ACK_thread 
{ 
    // wait for ack received flag to be set 
} 

會發生什麼事是,ACK BackgroundWorker的超時,並確認沒有收到。我相當肯定它是由遠程設備傳輸的,因爲該設備根本沒有改變,並且C#應用程序正在傳輸。我從這裏改變了ACK線程(當它工作)...

for(i = 0; (i < waitTimeoutVar) && (!bAckRxd); i++) 
{ 
    System.Threading.Thread.Sleep(1); 
} 

...這個...

DateTime dtThen = DateTime.Now(); 
DateTime dtNow; 
TimeSpan stTime; 

do 
{ 
    dtNow = DateTime.Now(); 
    stTime = dtNow - dtThen; 
} 
while ((stTime.TotalMilliseconds < waitTimeoutVar) && (!bAckRxd)); 

後者產生了非常acurate的等待時間相比前者。但是,我想知道是否刪除睡眠功能會干擾接收串行數據的能力。 C#是否只允許一次運行一個線程,也就是說,我是否必須讓線程在某個時間睡眠以允許其他線程運行?

任何想法或建議,你可能會感激。我正在使用Microsoft Visual C#2008速成版。謝謝。

回答

3

RX線程的「新」版本正在利用100%的處理器時間 - 它只是連續運行,從不休眠。除了這種方法的一般性質外,這個可能(雖然不是肯定)會阻止其他一些事情,比如接收數據,不能及時發生。

對於等待的情況就是這樣,一個通常會使用稱爲事件線程同步結構。您創建一個「事件」對象,並且RX線程在其上等待,而處理線程在接收到ACK時發信號通知事件。

AutoResetEvent event = new AutoResetEvent(false); 

// ... 
// ACK waiting thread: 
event.WaitOne(); 
// ... 

// ... 
// Whatever thread actually receives the ACK 
if (/* ack received */) 
{ 
    // bAckRxd = true; - comment this out. Replace with following: 
    event.Set(); 
} 

至於爲什麼你沒有收到你的ACK,我需要更多的信息。頻道究竟是什麼?它是串口嗎?網絡?管?還有別的嗎?

+0

謝謝,費奧多爾。這似乎是訣竅。我正在使用串行通信。 – 2010-05-11 20:34:34

+0

很高興幫助。別客氣。 :-) – 2010-05-11 22:25:24

3

要回答C#是否允許一次運行一個線程的直接問題,C#與線程無關。但是,.NET框架將允許您一次運行多個(邏輯)線程。實際如何處理是框架和操作系統的一個功能。

至於你的問題,我認爲你有太多的線程在等待狀態開始。發送和接收數據的方法應該有異步調用模型(Begin和End)。因此,您應該通過對Begin的調用來啓動傳輸,然後附加在函數終止時調用的回調函數。

然後,在回調中,您將處理結果並繼續執行下一個異步操作(如有必要)或更新UI。

1

你的代碼是相當快樂的。當你希望他們計時時,這確實會讓你陷入麻煩。特別是當您使用BGW或線程池線程時,調度程序只允許它們在沒有更多線程處於活動狀態時運行,而不是CPU核心。或者當線程「卡住」了一段時間。你的卡住了。您似乎也沒有有效地使用它們,輪詢循環會消耗大量不必要的CPU週期。

槓桿SerialPort類的功能,以避免這種情況:

  • 你不需要傳輸線程。串口驅動程序有一個緩衝區,當數據符合緩衝區時,Write()調用會立即返回。從主線程寫入很好。
  • 您不一定需要接收線程。串口已經有一個,它運行DataReceived事件。它可以碰撞您在傳輸數據時啓動的計時器。
  • SerialPort已具有ReadTimeout屬性。您可以在接收線程中使用它來超時Read()調用。

Sleep()不會干擾串行端口,它們的驅動程序使用硬件中斷讀取數據。

+0

是的,我同意。我消除了4個背景工作者中的2個,並實施了由Fyodor建議的AutoResetEvent。我將不得不仔細看看SerialPort類。謝謝。 – 2010-05-11 20:33:46

相關問題