7

シリアルポートが閉じ終わったときを把握しようとして髪を引っ張っているので、再び開くことができます。CloseHandle()ポートが実際にロック解除される前に戻ることが判明しました。

を使用してシリアルポートを開き、を使用CreateFile(FILE_FLAG_OVERLAPPED)してCompletionPortに関連付け、を使用してCreateIoCompletionPort()読み取り/書き込みを行い、を使用しReadFile()WriteFile()閉じていCloseHandle()ます。

シリアルポートをすばやく閉じて再度開くと、ERROR_ACCESS_DENIEDから戻ってくることに気づきましたCreateFile()CloseHandle()これは、戻るのを待ってから、そのハンドルに関連付けられているすべての未処理の読み取り/書き込み操作が完了ポートから戻るのを待っているにもかかわらず発生しています。確かにもっと良い方法があります:)

シリアルポートを同期的に閉じるにはどうすればよいですか?ループ、sleep()、またはその他の安価なハックを再試行しないでください。

編集:多分これは私の完了ポートとFILE_FLAG_OVERLAPPEDの使用と関係があります。読み取り/書き込み操作が完了すると、コールバックが返されます。ポートを閉じるための何らかのコールバックはありますか?

4

3 に答える 3

1

問題は、COM ポートを提供するドライバーにあると思います。したがって、COM ポートを「実際に閉じる」ための API はありません。

ところで、ファイル ハンドルを閉じた後、すべての未解決の I/O がエラーで完了するのを待つ必要はありません。CloseHandleすべての未処理の I/O が既に完了またはキャンセルされている状態で、コールバックを非同期に受け取るだけです (完了ポートまたは APC キューを介して)。

具体的には、FTDI ドライバー (COM->USB をエミュレートするドライバー) は非常にグリッチがあることが知られています。

ハンドルを閉じる前にデータをフラッシュすることをお勧めします。COM ポートを閉じる前に、すべての I/O が完了するのを待つことができます (これが該当する場合)。SetCommMaskまたは、 andを呼び出して、WaitCommEvent保留中の送信データがないことを確認することもできます。うまくいけば、これが役立つかもしれません。

編集:

CloseHandleすぐに (戻る前に) ファイルハンドルで保留中のすべての I/O をキャンセルしますか?

厳密に言えば、いいえ

ファイル オブジェクトへの他の参照が残っている可能性があります。たとえば、ユーザー モード コードが を呼び出すDuplicateHandle場合や、カーネル モード ドライバーが を呼び出す場合がありますObReferenceObjectByXXXX。このような場合、ハンドルが参照するオブジェクトは必ずしも解放されません。

最後のハンドルが閉じられると、ドライバーのハンドルがDispatchCleanup呼び出されます。これに従って、すべての未処理の I/O をキャンセルする必要があります

ただし、1 つのスレッドがCloseHandle- 内にある間は、理論的には別のスレッドから別の I/O を発行できます (運が良ければ、ハンドルは引き続き有効です)。I/O 関数 (WriteFileやなど) を呼び出している間、OS はオブジェクトへの参照カウンターを一時的に増やします。CloseHandleこれにより、別の I/O が開始される可能性がありますが、呼び出しによって直接キャンセルされることはありません。

ただし、この場合、オブジェクトへの参照カウントが再び 0 に達したため、新しい I/O が発行された直後に O/S によってハンドルが閉じられます。

そのため、このような倒錯したシナリオでは、呼び出しの直後にCloseHandleファイルを再度開くことができないという状況が発生する可能性があります。

于 2012-01-17T15:03:00.583 に答える
0

CloseHandle() リクエストを (おそらく他のスレッドで) 発行した後、デバイスに再度アクセスしようとする前に、リーダーとライターが (無効なハンドルで) 失敗することを確認してください。別の CreateFile を発行する前に、これを手掛かりとして使用して、すべての io 処理をクリーンアップできます。完了ポートは不必要にバロックに見えると言わざるを得ません。

于 2012-09-20T14:28:28.993 に答える