1

例外を発生させずに同じ ComDev で ReadFile を呼び出せるように、WriteFile 関数が UART への書き込みを完了しているかどうかを確認したいと考えています。

書き込みが完了する前にWriteFile 関数が返される可能性があるようです。

BOOL WriteCommBlock(HANDLE * pComDev, char *pBuffer , int BytesToWrite)
{
while(fComPortInUse){}

fComPortInUse = 1; 

BOOL       bWriteStat   = 0;
DWORD      BytesWritten = 0;
COMSTAT    ComStat      = {0};
OVERLAPPED osWrite      = {0,0,0};

if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
    short Errorcode = GetLastError();
    if( Errorcode != ERROR_IO_PENDING )
        short breakpoint = 5; // Error

    Sleep(1000); // complete write operation TBD

    fComPortInUse = 0; 
    return (FALSE);
}


fComPortInUse = 0; 
return (TRUE);
}

回避策として Sleep(1000) を使用しましたが、適切な時間を待つにはどうすればよいですか?

4

5 に答える 5

1

イベントを作成し、それをオーバーラップ構造に保存して、シグナルが送信されるのを待つことができます。このように(未テスト):

BOOL WriteCommBlock(HANDLE * pComDev, char *pBuffer , int BytesToWrite)
{
while(fComPortInUse){}

fComPortInUse = 1; 

BOOL       bWriteStat   = 0;
DWORD      BytesWritten = 0;
COMSTAT    ComStat      = {0};
OVERLAPPED osWrite      = {0,0,0};
HANDLE     hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (hEvent != NULL)
{
    osWrite.hEvent = hEvent;
    if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
    {
        short Errorcode = GetLastError();
        if( Errorcode != ERROR_IO_PENDING )
            short breakpoint = 5; // Error

        WaitForSingleObject(hEvent, INFINITE);

        fComPortInUse = 0; 
        return (FALSE);
    }
    CloseHandle(hEvent);
}


fComPortInUse = 0; 
return (TRUE);
}

他に何をしようとしているのかによっては、単に WaitForSingleObject() を呼び出すのが最善のアイデアではない場合があることに注意してください。また、INFINITE タイムアウトもありません。

于 2012-08-17T21:14:45.677 に答える
1

あなたの問題は、UART や基礎となるデバイスに関係なく、重複した I/O を誤って使用することです。

コードを修正する最も簡単な (必ずしも最適であるとは限りません) 方法は、イベントを使用して I/O 完了を処理することです。

// ...
OVERLAPPED osWrite      = {0,0,0};

osWrite.hEvent = CreateEvent(FALSE, NULL, NULL, FALSE);

if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
    DWORD Errorcode = GetLastError();
    // ensure it's ERROR_IO_PENDING

    WaitForSingleObject(osWrite.hEvent, INFINITE);

}

CloseHandle(osWrite.hEvent);

ただし、I/O 全体が同期していることに注意してください。これは OS によって非同期的に処理されますが、コードは完了するまで続きません。もしそうなら、なぜ重複した I/O を使用するのですか?

これを使用して、同じスレッド内で複数の I/O (およびその他のタスク) を同時に処理できるようにする必要があります。これを正しく行うには、OVERLAPPED構造体をヒープに割り当て、使用可能な完了メカニズムの 1 つ (イベント、APC、完了ポートなど) を使用する必要があります。プログラム フロー ロジックも変更する必要があります。

于 2012-08-17T21:20:10.897 に答える
0

役に立たないので、 writefileSleep(1000);が操作を完了した後にのみ実行されます。WriteFileが終了するまで待つ必要があります。

if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{}

条件文内のすべては、結果がtrueの場合にのみ実行されることを知っている必要があります。そして、ここでは、WriteFileルーチンの完了後(完了またはエラーの有無にかかわらず)、結果がプログラムに送信されます。

于 2012-08-17T21:08:17.653 に答える
0

OK、読み取り/書き込みコードでオーバーラップした I/O OVL パラメータを見逃していたので、昨日コメントとして返信しただけでも問題ありません。

オーバーラップされた I/O を処理する従来の方法は、オーバーラップされた読み取り/書き込み呼び出しで発行されるバッファー クラスのデータ メンバーとして _OVL 構造体を使用することです。これにより、読み取り呼び出しと書き込み呼び出しを同時にロードすることが容易になります (実際には、個別のバッファー インスタンスを使用した複数の読み取り/書き込み呼び出し)。

COM posrt の場合、私は通常、readFileEx/writeFileEx API でアドレスが渡される APC 完了ルーチンを使用します。これにより、_OVL の hEvent フィールドがバッファのインスタンス ポインタを保持するために自由に使用できるようになるため、完了ルーチン内で簡単にキャストし直すことができます (つまり、各バッファ クラス インスタンスには、バッファクラスインスタンスへ - 奇妙に聞こえますが、正常に動作します)。

于 2012-08-18T08:30:48.367 に答える
0

非同期 I/O が必要だとは言っていないので、同期を試す必要があります。それは簡単です。OVERLAPPED 引数に null ポインターを渡すだけで、同期、ブロッキング、I/O が得られると思います。このドキュメントの「Windows C」セクションで私が書いたサンプル コードを参照してください。

http://www.pololu.com/docs/0J40/

于 2012-08-17T21:30:04.797 に答える