2012-04-12 13 views
5

SerialPortクラスとThreadPool.QueueUserWorkItemまたはTaskのいずれかを使用して、C#.Net 4.0アプリケーションで興味深い問題が発生しました。.Netスレッド対ThreadPortool対SerialPort通信のタスク

2つ以上のSerialPortsを同時に使用する場合にのみ問題が発生します。各シリアルポートは、私は3つの方法の1で作成した独自のスレッドで実行されます:問題を説明するために

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

、私は読んで私のDoSerialCommXメソッドを作成しましたシリアルポートへの書き込みは永久にループします。これは次のように見えます:(実際のプログラムでは実際にこれをやっているわけではありませんが、問題を特定して説明するテストプログラムのスニペットです)。

方法2または3のいずれかを使用すると、シリアル通信が途切れ、多くの通信タイムアウトが発生します。方法1を使用すると、すべてが良好です。また、これは私のIntel AtomベースのPCでのみ発生すると言えます。デスクトップPCに問題はないようです。

私はスレッドプールがスレッドを再利用することを知っており、デフォルトではTaskはスレッドプールを使用します。スレッドプールは実際に短命の操作を意図していることがわかりました。しかし、私は​​を使ってみましたが、これはスレッドプールを使用するのではなく、専用のスレッドを生成すると思っていましたが、それでも動作しませんでした。

質問:なぜこのような状況でThreadが特別なのですか? ThreadにはIO操作に適していますか?

編集: 答えはこれまでのところ、私は決して終わることのないプロセスのためのThreadPoolやタスクを使用しようとしていますことを前提としているようです。私の実際のアプリケーションでは、そうではありません。私は問題を説明するために上のコードで終わりのないループを使用しています。私は実際にThreadがなぜ働き、ThreadPoolTaskでないのかを知る必要があります。シリアル通信が問題になる原因とは、技術的にどのような違いがありますか?

+0

私はそれが愚かな質問だと思うが、あなたは> 25スレッドを管理しようとしていないのですか? – Jeff

+0

@ JeffN825、いいえ、シリアルポートあたり1つのスレッドしかなく、最大4つのシリアルポートを使用しています。 – Verax

+0

1および3は同じである。 –

答えて

2

哲学的には、実行スレッドがどのように動作するかに1,2,3の違いはほとんどありません。それらはすべて、あなたがそれを上書きしない限り同じデフォルトの実行優先順位を共有します - 概念的には、スレッドスケジューラはそれらをスケジュールするために同じ戦略を使用します。彼らは皆、楽しくループして座っていました。

私は方法の間に大きな差がある疑いがある:

  1. インフラコスト(スレッド、メモリなど)は、あなたの実行をクロックタイムスライスを競合するすべてのそれらの#2のスレッドプールをサポートするために、スピンアップと#3ループ。
  2. 筋肉の少ないAtomのスレッドコンテキスト切り替えコスト。 Atomには、より小さなキャッシュ、 と短い処理パイプラインがあります。より多くの実行スレッド=より多くのコンテキストスイッチ、より多くのパイプラインのダンプ、および命令キャッシュ効率の低下。

方法2と3の機能的な観点からは、方法2と3の使い方はやや乱暴ですが、その方法を決して終了しないことです。これらの戦略は、アトミック、有限の操作、および非同期ネットワーク、ディスク操作などのIO完了ポートタスクに適したいくぶん無計画な実行に最適化されています。(シリアルポートコードの可能性もありますか)

Async IOへの適応に興味がある場合を除き、2 &をスキップしてください。スレッドに焦点を当てる - スレッドプールがもたらすインフラストラクチャのオーバーヘッドなしに、より細かい粒度、予測可能な実行制御を望んでいるようです。タイムアウトを引き起こした -

+1

9600ボーのシリアルポートです!ミリ秒ごとに1文字。 UARTにはハードウェアバッファがあり、ドライバにはバッファがあります。これらの2つのポイントのいずれかがここで問題になる可能性があるという信念をほとんど超えています。 –

+0

私のAsus原子パワーラップトップ(!)は、問題なく115Kbaudで2つのシリアルポートをうまく実行します。一般的にハードウェアではありません(もちろん、OPの箱は悪いかもしれません)。 –

0

は若干の違いがあります。Thread.Start()が呼び出さ ときにスレッドを使用して

  • が明示的に新しいスレッドを作成 - そしてそれはあなたのコードは、特定の瞬間ことを実行することを保証します。
  • ThreadPoolを使用すると、内部のThreadPoolロジックに従って、近い将来に にスレッドが開かれます。 ThreadPool の番号は限られているので、実行中の長い(または無限の) に使用することをお勧めします。
  • タスクを使用すると、コードが実行されると判断されます。 のいずれかのスレッドまたはメインスレッドであっても、 がすぐに実行されたり、別のタスクが異なる スレッドで実行されることはありません。

タスクをすばやく開始したい場合は、常にスレッドを使用してください。 TasksとThreadPoolの両方に、あなたが気付いたわずかな遅延を引き起こすかもしれないいくつかの追加の "インフラストラクチャオーバヘッド"があります。

あなたのタスクが存在しないときにThreadPoolとタスクの両方が使用されることはないので、あなたはThreadを使うことをお勧めします。

1

これは、あなたがCOMポートから読み書きしているために起こると思われます。この要素がなければ、これらのすべてが同じように実行されるはずです(チェックすると、すべてが標準優先順位のスレッドで実行されているためです)。

I/O completion portsとスレッドプールでこの奇妙な動作を説明できるかどうかを確認することがあります。

+0

私はあなたが正しいと思います。シリアルポートはこの問題の重要なコンポーネントです。あなたは多分I/O完了ポートの提案を詳しく説明できますか? – Verax

+0

I/O完了ポートの動作の詳細については、http://hi.baidu.com/jrckkyy/blog/item/401422527c131b070df3e37b.htmlも参照してください。 –

1

あなたのコード、ドライバ、ハードウェアには、シリアルポートのパフォーマンスを「エッジ」に置いているものがあります。専用のスレッドやスレッドプールを使用しても問題はありません(シリアルポートの読み込みをブロックするためにスレッドプールスレッドを使用する)。

2つの9600ボー・シリアル・ポートは、ビーズとワイヤーに十分な油を注いでいるので、あなたはアバカスで走ることができます。

+0

Puh。私は簡単に2つの9600ボーのシリアルポートを錆びた玉ねぎで走らせることができます。 –

+0

これは問題ありません。あなたはたぶんhyperBeadsを持った複数のワイヤーバーを持っています。 –