#### 追記

多数のご意見ありがとうございます。編集しました。  
利用デバイスについての詳細は避けさせて頂きたいのですが、可能な限りで情報を記載しました。

### 前提条件

Windows10環境、言語はC# で、.NetFramework4.6.2
を用いて、あるデバイスのデータを取得してユーザーに提供するdllを作成しています。

あるデバイスは、WindowsPCとは独立したデバイスで、自身のクロックでデータを取得していき、そのデバイスの中にデータを蓄えていきます。そのバッファはFIFOのような形で、そのデバイスのドライバが提供するAPIを用いてデータを取得可能です。

### デバイス仕様/利用イメージ

①PCI、USB等がありますが、APIは同じです。  
②データ取得開始のAPIを叩くと、データ収集が開始されます。  
③データ収集が開始され、「一定数以上のデータが溜まるとイベントが発生」し、そのイベントの中で、データ回収処理を行います。（イベント発生データ数は初期処理で別途設定）  
④デバイスの中のバッファに再びデータが溜まり、イベントが起きて、データ回収してと繰り返します。

### 相談事項

相談したいのは、そのデバイスからデータを取得する処理でして、基本的に以下のような処理になりまして、定期的に実行されるイメージです。

① デバイス内のデータが一定数溜まるとイベントが発生  
② デバイス内データ数を取得するAPIを実行し、溜まっているデータ数を確認  
APIイメージ：GetDataCount（out DataCount）;  
③ ②で確認したデータ数分のInt32配列を確保  
④ デバイス内データを取得するAPIを実行し、②で確認したデータ数を指定して、③で確保した配列にデータを取得  
APIイメージ：GetData（DataCount, out DataArray[DataCount]）  
⑤ ④で取得したデータを別の配列に連携

上記で上手くいくと思っていたのですが、他の処理(別スレッドで画面にデータを表示する処理など)が重なったりすると、①でデータ数を確認してから、③でデータを取得するまでに遅延が発生し、デバイス側のバッファに予想以上のデータが溜まってしまう現象が起きます。

上記は、デバイスが「データが一定数溜まったら」イベントを発生させるという仕様でデータ回収する都合上で問題があります。

具体的には、以下のイメージです。（前提として、1000個でイベント発生とします。）

  1. デバイスでイベント発生：この時点で1000個溜まっている
  2. デバイスのデータ数を確認：1100個等のデータを確認（イベント発生後もデータ収集自体は続いているので）
  3. 1100個分の配列を確保
  4. デバイスから、1100個分のデータを取得  
→この時、デバイス内データが1000個以下なら、暫くして再度データ収集可能ですが、仮に2～4の間でデータ回収に時間がかかると、4の処理が完了した後にデバイス内のデータ数が1000個以上あると、次のイベントが発生せず、データ収集処理が走らなくなり、オーバーフローエラーが発生します。

出来れば、①から③の処理が終わるまで、他の処理が割り込むのを禁止するような処理があれば良いと思っております。

調べていると、Threadを利用して、①～③を優先度：Highestで実行するなどがありそうなのですが、もしも他に良さそうな処理があればご助言を頂くことは可能でしょうか。

上記はデバイスメーカーに相談したのですが、データ回収処理の優先度を上げる（質問事項です。）か、定期的にデータ数を確認してデータを回収してほしいと回答を受けました。

ただ、定期的にデータ数を確認する場合、アプリ側で常にデータ数を確認する必要があり、出来ればデバイスから発生するイベントで回収したいと考えておりました。
CC BY-SA 4.0
2023-04-13T13:20:24.427
94508
2023-04-20T11:12:53.117
2023-04-18T01:03:15.763
3060
57915
question
c# windows .net
C#において、ある処理の間は他の処理を割り込ませないようにする方法について、アドバイスいただけないでしょうか
考えられるのは以下の2点くらいでしょうか。

  * デバイスドライバにそうした処理を組み込む/既にあるならバッファサイズを拡張する
  * C++でそうした処理を行うサービスや常駐プロセスを作って動作させ、dllはそれとのインターフェースを取るための手段とする

とにかく.NET側で何かしようとせずに、他に任せた方が良いでしょうね。

**説明追記**  
微妙にC++の受けが悪いようですが、上記の肝はコメントに書いたように同一プロセスの中のユーザーコードでUI/表示処理と通信処理を両方行おうとするのはやめた方が良いということです。

デバイスドライバに機能があればカーネルモードで通信処理の重要な部分を任せられるのでユーザーコードはUI/表示処理に注力できます。  
(質問に追記された内容により、それは望めそうも無い感じですが)

そして通信処理とUI/表示処理を別々のプロセスに分ければ、それぞれは独立して動作しているので「ある処理の間は他の処理を割り込ませないようにする」ことは1つのプロセス内でテクニックを駆使するよりは自然と達成出来てしまうものです。  
そういう意味では通信処理がC#のままでも実現出来るし、C++で作ったとしても必ずしも問題解決にはつながらないと言うのはその通りです。

しかし質問に書かれた以外にも何か問題が有って対処が必要になった時にC++で作っておいた方がMutex,Event,デバイスのOverlappedMode,WaitForSingleObject/WaitForMultipleObjects,CancelIoといったWin32APIを直接使う設計や実装が簡単になるし、Framework,CLR,ILやP/Invoke,Marshallingといったわずかながらも間接的/オーバーヘッドになりうる部分や処理を省けることで、問題が発生する可能性を減らすことが出来ると考えられるからです。

2つのプロセス間の通信は名前付きパイプのメッセージ転送モード・非同期オプション付きとかで実装出来るのではないでしょうか？

* * *

更新された質問内容について

質問に追記された情報を見ると、デバイスドライバは(おそらく処理の簡略化のために)対象デバイスにコマンドを送信し、該当データをデバイスから受け取る処理だけをやっているようですね。  
つまりデバイスドライバはインタフェース変換をやっているだけでデータのフロー制御には関わっていないものと思われます。

現状のままで一番簡単に試せる方法としては、以下の3点を併用してみてはどうでしょう？

  * イベント発生データ数の設定を減らしてデバイス内のバッファの使用率を下げてみる  
イベント発生データ数をデバイスバッファの1/3から1/4程度(あるいはもっと小さく)に設定すれば、多少処理が遅くなってもバッファがオーバーフローする前に処理出来るのでは？

  * 最後のイベント発生/処理時刻を記憶しておいて、それと現在時刻との間が通常の処理時間よりも開いていたら、何かで処理の遅延していると判断してデータ回収処理を強制的に行う  
それをUIや画面更新処理の途中/要所々々でチェックを行うよう組み込めば良いのでは？

  * 1回分のデータ回収処理を終えた最後に、再度デバイスバッファに溜まっているデータ数を取得し、それが設定したイベント発生データ数以上(あるいはそれより少なかったとしても十分大きな数)だったら、次のイベントを待たずに次のデータ回収処理を行う
CC BY-SA 4.0
2023-04-13T14:56:53.820
94511
2023-04-20T04:19:50.610
2023-04-20T04:19:50.610
26370
26370
94508
answer
対策を行う前に原因を特定することをお勧めします。そうでないと無関係で効果のない対策になりかねないです。

「①でデータ数を確認してから、③でデータを取得するまでに遅延が発生し」は考えられる原因候補ではありますが、単なる推測ではないでしょうか？
[Stopwatchクラス](https://learn.microsoft.com/ja-
jp/dotnet/api/system.diagnostics.stopwatch?view=netframework-4.6.2)などで所要時間を測定して原因かどうかを明確にしてください。

「デバイス側のバッファに予想以上のデータが溜まってしまう」は観測された事実かのように記述されていますが、実際のところはどうでしょうか？
③の前または後に再度溜まっているデータ数を確認されましたでしょうか？
そうではなくこれすらも推測ですと質問文には何の情報もなく、全く別のところに原因が存在する可能性も考えられます。

また想定される具体的なデータ量も提示してください。10Gbps NICで1GB/sのデータ処理が必要とかそういう状況なのでしょうか？
あてずっぽうですが、今どきのコンピューターであれば1MB/s程度なら、プログラムを適当に組んでも取りこぼすことはないような気がします…。

* * *

>
> この時、デバイス内データが１０００個以下なら、暫くして再度データ収集可能ですが、仮に２～４の間でデータ回収に時間がかかると、４の処理が完了した後にデバイス内のデータ数が１０００個以上あると、次のイベントが発生せず、データ収集処理が走らなくなり、オーバーフローエラーが発生します。

当初の質問には「イベント」という記載はありませんでした。「イベント」の発生条件の厳密な仕様を把握できていないことが原因ではありませんか？
つまり極稀にイベントの発生条件を満たしておらず待ちぼうけになっている可能性が考えられます。「エージング等で24時間以上回していると、データが回収されない現象が発生」も発生条件を満たす確率が低いだけで、条件を満たせば100%発生するのではと思います。

例えば1バイトでもデータが残っていたらイベントが発生しないという仕様の場合、スレッドのプライオリティをどんなに上げても「②データ数を確認」～「④データを取得」をゼロにすることはできません。仮にそのような仕様の場合は「④データを取得」の後に再度「データ数を確認」を行い、バッファが空になるまで繰り返す必要があります。

もしくは「データを取得」の仕様として大きめのバッファを渡した場合に読めるだけ読んで返してくれるのであれば、「④データを取得」で大きめのバッファを渡すことでも改善します。PCの搭載メモリに対してデータサイズが十分に小さいのであれば、「②データ数を確認」の２倍を確保するとか、「②データ数を確認」を実行せずに1MB決め打ちで確保するとか。それらも既に述べたようにデータ量を把握したり、各処理の所要時間を把握すれば、どのように設計すればいいかは見えてくるはずです。

> 定期的にデータ数を確認する場合、アプリ側で常にデータ数を確認する必要があり、出来ればデバイスから発生するイベントで回収したいと考えておりました。

「イベント」に対して行う処理（イベントハンドラ）をアプリ側で定期的に発報するタイマーからも呼び出せばいいのでは？
ただし根本的な解決とはならないのでお勧めはしません。

* * *

kunifさんの回答でC++言語が提案されている件について

質問文には「他の処理(別スレッドで画面にデータを表示する処理など)が重なったりすると」とあります。基本的にスレッド間は独立していて別スレッドの処理が重くなっても影響は受けません。もちろん影響を与える高負荷も存在しますが、その場合はC++言語での実装に切り替えても同様に影響を受けます。そのため、本件に関して
C# を他の言語に変更しても問題解決にはつながらないと考えられます。
CC BY-SA 4.0
2023-04-13T22:18:53.643
94513
2023-04-19T19:12:11.900
2023-04-19T19:12:11.900
4236
4236
94508
answer
そもそも、

> ② デバイス内データ数を取得するAPIを実行し、溜まっているデータ数を確認  
>  APIイメージ：GetDataCount（out DataCount）;  
>  ③ ②で確認したデータ数分のInt32配列を確保  
>  ④ デバイス内データを取得するAPIを実行し、②で確認したデータ数を指定して、③で確保した配列にデータを取得

がきちんとできているのであれば、②と④の間にどれだけ時間が経とうが、どれだけイベントが発生しようがエラーなどは起こりえません。

ピント外れな対策に頭を悩ませる前に、きちんとそのエラーの原因を突き止めましょう

追記  
処理中にデータが溜まってしまうとまずいってことだと思われますが、それははたしてWindows側で処理を止めればデータが溜まることはなくなるんでしょうか？

相変わらずピント外れな解決法なように思われますが。

そもそもその設計そのものから見直さないとダメな気がします
CC BY-SA 4.0
2023-04-19T00:07:01.610
94568
2023-04-20T11:12:53.117
2023-04-20T11:12:53.117
27481
27481
94508
answer