質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

1回答

20592閲覧

SerialPortクラスのDataReceivedイベントが発生しなくなる

koao

総合スコア7

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

1クリップ

投稿2018/02/05 04:41

現在複数のCOMポートを扱うプログラムを制作しています。
DataReceivedイベントの中で電文をすべて受信する為にThread.Sleepで待機しているのですが、
Thread.Sleepを入れると他のCOMポートのDataReceivedイベントが発生しなくなります。
どうやらスリープしている間発生しないということでもないようですが、スリープの秒数が長いほどイベントが発生しない可能性が高いです。
なぜこのようなことが起きるのか、どうすれば解決するのか皆目見当がつきません。どなたかご教示いただけますでしょうか。何卒よろしくお願いいたします。

下記ソースコードは2つのポートに接続し、定期的にデータを送信するプログラムです。SP1は送信後最大500ms秒間DataReceivedイベントが発生するか待機しメッセージを表示します。
SP2は定期的にデータを送信し、DataReceivedイベントが発生したタイミングでThread.Sleepを実行します。
両方接続先は何らかのデータを送信すると即座に文字列を返すポートに接続してテストを行いました。

該当のソースコード

C#

1using System; 2using System.Diagnostics; 3using System.IO.Ports; 4using System.Threading; 5using System.Threading.Tasks; 6 7namespace SerialPortReceTest 8{ 9 class Program 10 { 11 static SerialPort SP1 = new SerialPort("COM10",19200, Parity.Even,8, StopBits.One); 12 static SerialPort SP2 = new SerialPort("COM12", 9600, Parity.None,8, StopBits.One); 13 14 static bool responded = true; 15 16 static void Main(string[] args) 17 { 18 19 20 SP1.DataReceived += SP1_DataReceived; 21 SP2.DataReceived += SP2_DataReceived; 22 23 Task task = Task.Factory.StartNew(() => { 24 int timeOutMs = 500; 25 Stopwatch sw = new Stopwatch(); 26 27 while (true) 28 { 29 30 if (SP1.IsOpen) 31 { 32 responded = false; 33 34 byte[] buff = new byte[] { 0x31, 0x31, 0x31 }; 35 SP1.Write(buff, 0, buff.Length); 36 37 sw.Start(); 38 while (sw.ElapsedMilliseconds < timeOutMs && !responded) 39 { 40 Thread.Sleep(0); 41 } 42 sw.Reset(); 43 44 if (responded) 45 { 46 Console.WriteLine("There response"); 47 } 48 else 49 { 50 Console.WriteLine("No response "); 51 } 52 53 } 54 55 Thread.Sleep(20); 56 57 } 58 }); 59 60 Task task2 = Task.Factory.StartNew(() => { 61 while (true) 62 { 63 if (SP2.IsOpen) 64 { 65 byte[] buff = new byte[] { 0x31, 0x31, 0x31 }; 66 SP2.Write(buff, 0, buff.Length); 67 } 68 69 Thread.Sleep(100); 70 } 71 }); 72 73 SP1.Open(); 74 SP2.Open(); 75 76 Console.ReadKey(true); 77 } 78 79 private static void SP1_DataReceived(object sender, SerialDataReceivedEventArgs e) 80 { 81 responded = true; 82 SP1.DiscardInBuffer(); 83 } 84 85 private static void SP2_DataReceived(object sender, SerialDataReceivedEventArgs e) 86 { 87 Console.WriteLine("sleep start"); 88 Thread.Sleep(100000); 89 Console.WriteLine("sleep end"); 90 SP2.DiscardInBuffer(); 91 } 92 93 } 94}

スリープあり

sleep start No response There response No response There response No response No response There response No response No response No response No response No response There response No response No response No response No response No response There response No response No response

スリープなし

There response There response There response There response There response There response There response There response There response There response There response There response There response

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2018/02/05 06:47 編集

再現しないと思って色々書きましたがミスってました。再現したのでちょっと見てみます。
koao

2018/02/05 08:29

よろしくお願いいたします。
guest

回答1

0

ベストアンサー

DataReceivedイベントハンドラが実行される際には、ハンドラはThreadPoolのキューに登録されます。
このプログラムでは、SP2_DataReceivedは、100ms毎に3個ずつキューに登録されることになります。
従って、100000msスリープしている間に、3000個分がThreadPoolのキューに登録されてます。

SP1_DataReceivedハンドラも、受信時にはThreadPoolのキューに登録されます。

ThreadPoolは、プロセスに1つしかなく、実際に利用できるスレッドが空いたら、キューから取り出して実行されます。

このプログラムで起きている現象は、SP2_DataReceivedがキューに溜まりすぎて、SP1_DataReceivedがディスパッチされていないのが原因と思われます。

投稿2018/02/07 05:17

編集2018/02/07 06:49
Harahira

総合スコア243

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koao

2018/02/07 07:22

回答ありがとうございます。 スレッド プールの最小値に達するとタスクが完了するか、追加のスレッドが作成されるまで待機するようで、追加のスレッドを作成するペースが遅い為にこういう状態になったということみたいです。 スレッドプールの最小値を上げることで改善されました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問