2012-04-12 103 views
5

我遇到了一個有趣的問題,在我的C#.Net 4.0應用程序中使用SerialPort類和ThreadPool.QueueUserWorkItemTask s。.Net線程與線程池vs任務串口通信

如果我同時使用2個或多個串行端口,則只會出現此問題。每個串口在自己的線程中運行,我創建1 3的方式:

  1. new Thread(DoSerialCommX)
  2. ThreadPool.QueueUserWorkItem(DoSerialCommX)
  3. new Task(DoSerialCommX, TaskCreationOptions.LongRunning).Start()

爲了說明這個問題,我創建了DoSerialCommX方法來讀取並永遠在一個循環中寫入串行端口。它看起來像這樣:(我實際上並沒有在我的真實程序中這樣做,這只是我測試程序中的一個片段,它隔離並說明了問題)。

private void DoSerialCommX() 
{ 
    SerialPort port = new SerialPort("ComX", 9600); 
    port.Open(); 

    while(true) 
    { 
     //Read and write to serial port 
    } 
} 

如果我使用方法2或3,串行通信口吃和我收到很多通信超時。如果我使用方法1,一切都很好。另外,我應該提到這似乎只發生在我的基於Intel Atom的個人電腦上。臺式電腦似乎沒有問題。

我知道線程池重用線程,並且默認Task使用線程池。而且我知道線程池真的用於短期操作。但我嘗試使用​​,我認爲它會產生一個專用線程而不是使用線程池,但它仍然無法工作。

那麼問題:是什麼讓Thread在這種情況下如此特別?是否有關於Thread的更多信息使其更適合IO操作?

編輯: 答案迄今似乎認爲我試圖使用線程池或任務的一個永無止境的過程。在我的真實應用中,情況並非如此。我只是在上面的代碼中使用了一個永無止境的循環來說明問題。我真的需要知道爲什麼Thread工作和ThreadPoolTask不。他們在技術上有什麼不同,會導致串行通信打嗝?

+0

我想這是一個愚蠢的問題,但你並沒有試圖管理> = 25線程,是嗎? – Jeff 2012-04-12 04:49:55

+0

@ JeffN825,不,每個串口只有1個線程,而且我最多使用4個串口。 – Verax 2012-04-12 06:16:11

+0

1和3是一樣的。 – 2012-04-12 08:35:17

回答

2

哲學上,在執行線程的行爲方式中,1,2和3之間幾乎沒有區別。它們都具有相同的默認執行優先級,除非您重寫它 - 理論上線程調度器將使用相同的策略來調度它們。他們都高興地坐在循環中。

我懷疑方法之間的較大差異是:

  1. 基礎設施成本(線程,內存等),紡爲支持的#2,#3線程池,所有這些都將爭奪的時鐘時間片與執行循環。
  2. 線程上下文切換成本較低肌肉的Atom。 Atom擁有更小的緩存, 和更短的處理管道。更多的運行線程=更多的上下文切換,更多的管道轉儲以及更低的指令緩存效率。

從功能的角度來看,方法2和方法3的使用有些濫用 - 您的意圖是永遠不會退出該方法。這些策略針對原子操作和有限操作進行了優化,並且適用於IO完成端口任務(如異步網絡,磁盤操作等)(可能也有可能是您的串口代碼?)。

我會除非您有興趣適應Async IO,否則跳過2 & 3。專注於線程 - 看起來像你想要更細粒度,可預測的執行控制,而沒有Threadpool帶來的基礎架構開銷。

+1

這是一個9600波特串口!每毫秒一個字符。 UART有一個硬件緩衝區,驅動程序有一個緩衝區。幾乎無法相信這兩點中的任何一個都可能成爲一個問題。 – 2012-04-12 08:39:17

+0

我的華碩原子筆記本電腦,(!),將愉快地運行115Kbaud兩個串口沒有問題。這不是一般的硬件,(但是,當然,OP的盒子可能不好)。 – 2012-04-12 08:41:47

0

有細微的差別 - 這引起了超時:

  • 使用線程明確地創建一個新線程時Thread.Start()是 叫 - 它確保您的代碼運行特定的時刻。
  • 使用ThreadPool可確保根據內部ThreadPool邏輯將在將來 未來打開一個線程。由於ThreadPool 數量有限,建議將其用於長時間(或無限) 運行操作。
  • 使用任務只會確定代碼將運行。或者在 的另一個線程上,或者在主線程上,並且不確保它將立即運行,或者不同的任務將在不同的線程上運行。

所以如果你想讓你的任務快速啓動,總是使用線程。任務和ThreadPool都有一些額外的「基礎架構開銷」,可能會導致您注意到的輕微延遲。

由於ThreadPool和任務都不是用來當你的任務不存在時我建議你使用Thread。

1

我懷疑會發生這種情況,因爲您正在從COM端口讀取/寫入數據。如果沒有這個因素,所有這些應該以相同的方式執行,因爲(如果您選中)它們都運行在具有普通優先級的線程中。

也許讀了I/O completion ports和線程池,看看是否可以解釋這種奇怪的行爲。

+0

我認爲你完全正確。串口是這個問題的關鍵組成部分。你可以詳細說明I/O完成端口的建議嗎? – Verax 2012-05-01 05:14:46

+0

有關I/O完成端口如何工作的更多信息,另請參閱http://hi.baidu.com/jrckkyy/blog/item/401422527c131b070df3e37b.html。 – 2012-05-01 07:27:39

1

您的代碼,驅動程序或硬件使您的串行端口性能處於「邊緣」,以至於處於無法工作的邊緣。使用專用線程或線程池應該沒有問題(使用線程池線程阻塞串口讀取)。

兩個9600波特串口你可以用一個算盤運行,提供的珠子和電線已經上油。

+0

Puh。我可以在生鏽的算盤上輕鬆運行兩個9600波特串口。 – 2012-04-12 10:09:30

+0

這對你很好。你可能有一個多珠子的多線算盤。 – 2012-04-12 14:06:46