12
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

不幸にもSerialPortクラスのDataReceivedイベントで例外を発生させてしまった人にMSDNが提示した回避の方法がレガシーすぎる件

Last updated at Posted at 2016-05-18

これは増えすぎた地球の人口よりも多くのデバイスで走るCOMポートをC#などで操作しようとしたとき、割としばしば起こる"有効ではないスレッド間の操作"例外の回避方法についての補足である。

一般にはレガシーデバイスとみなされるCOMポートであるが、このデバイスは産業用途では今でも十分現役である。さまざまな機器がRS-232CやRS-485によるリモートコントロールをサポートしているので今でもSerialPortクラスの恩恵にあずかっているプログラマーは少なくない。

ところでSystem.IO.Ports.SerialPortクラスが発生させるDataReceivedイベントは次のような説明になっている。

DataReceived からデータを受信すると、セカンダリ スレッドでイベントが発生する、 SerialPort オブジェクトです。このイベントは、セカンダリ スレッドで発生されるため、メイン スレッドではなく、UI 要素など、メイン スレッドの一部の要素を変更しようとしています。 スレッド処理、例外を発生させる可能性があります。メイン ページでの要素を変更する必要がある場合は、 Form または Control, 、投稿の変更要求を使用して Invoke, 、これは適切なスレッドで処理を行います。

SerialPort.DataReceived イベント (MSDNより)

お分かりいただけただろうか。Control.Invokeメソッドが回避方法として提案されているが、この方法はWindows.Formsに依存しているのでWPFなどを使用している場合には採用しにくいのである。

この問題をより抜本的に解決するにはSystem.Threading.SynchronizationContextクラスなどが使用できる。クラス名で検索すれば詳しい仕組みや使い方はいくらでも出てくるのでここでは割愛するが、要はSynchronizationContextオブジェクトを事前にメインスレッドで生成しておいて、これにイベントハンドラの中身のうちメインスレッドに依存するオブジェクトに対する処理を委譲すればいい。

12
14
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?