0

私は使用しようとしているSetEventのでWaitForMultipleObjects、イベントを使用して同期したい関数をいくつか書きました。最初の関数を実行してから、2番目の関数を実行するように通知し、次に最初の関数を再度実行するように通知します。

2 つのイベントが作成され、1 つはシグナル状態に初期化され、もう 1 つは非シグナル状態に初期化されました。実行を期待どおりに実行できる唯一の方法は、各スレッドを 10 ミリ秒スリープ状態にすることです。SetEvent の使用に関するいくつかの警告について読みました: http://cboard.cprogramming.com/windows-programming/100818-setevent-resetevent-3.html

私の質問は、これらの関数呼び出しが実際にイベントを通知するために余分な時間を必要とするため、スレッドをスリープ状態にする必要があるかどうかです。デバッグ時に、設定されているイベントが未通知のままになることがあります。プロセス エクスプローラーを使用してこれを確認します。私のコードは基本的に次のようになります。

概して:

//1. FinCalcpidUpdatestruct <<  initialize to unsignalled
//2. FinUpdatestructCalcpid << initialize to signalled
FinCalcpidUpdatestruct = CreateEvent (NULL, FALSE, FALSE, TEXT("FinCalcpidUpdatestruct"));
FinUpdatestructCalcpid = CreateEvent (NULL, FALSE, TRUE, TEXT ("FinUpdatestructCalcpid"));


void function1()
{
    int n;
    int noGoCode;
    n=0;

    noGoCode = 0;
    while(1)
    {
    //Sleep(10);
    noGoCode = WaitForSingleObject (FinCalcpidUpdatestruct, INFINITE);
    if (noGoCode == WAIT_OBJECT_0) {

    //wait for FinCalcpidUpdatestruct to be signalled
    BufferOut[n] = pid_data_array -> output;

    //signal FinUpdatestructCalcpid 
    if(!SetEvent (FinUpdatestructCalcpid))
        printf("Couldn't set the event FinUpdatestructCalcpid\n");
    else{
        printf("FinUpdatestructCalcpid event set\n");
        Sleep(10);
        }
    }
    else
        printf("error\n");
    }
}

void function2()
{
    int nGoCode = 0;
    while(1)
    {
    //wait for FinUpdatestructCalcpid to be signalled

    // Sleep(10);
    nGoCode = WaitForSingleObject (FinUpdatestructCalcpid, INFINITE);
    if (nGoCode == WAIT_OBJECT_0) {
    if(!SetEvent (FinCalcpidUpdatestruct))
        printf("Couldn't set the event FinCalcpidUpdatestruct\n");
    else{
        printf("FinCalcpidUpdatestruct event set\n");
        Sleep(10);
        }
    }
    else
        printf("error\n");
    }//end while(1)

スリープが使用されていない場合、2 つの関数間でピンポンを行ったり来たりする代わりに、同じ関数が while ループを数回実行することがあります。何か案は?

4

3 に答える 3

3

printf各関数のSetEvent呼び出しの上にa を追加することで問題を解決できます。

問題は、イベントを設定してから出力を実行していることです。

function2の後printfに発生しますSetEvent

// Add a printf call here to see sensible output.
if(!SetEvent (FinUpdatestructCalcpid))
    printf("Couldn't set the event FinUpdatestructCalcpid\n");
else{
    // Thread is pre-empted by kernel here.  This is not executed immediately
    printf("FinUpdatestructCalcpid event set\n");
}

カーネルは実行中のスレッドを先取りするfunction2ため、FinUpdatestructCalcpidイベントは設定されてprintfいますが、期待していたものはありません。

次に、実行中のスレッドが実行され、イベントfunction1が設定されます。FinUpdatestructCalcpid実行中のスレッドの実行function2が許可され、中断したところから続行されます。printfイベントが設定されているため、FinUpdatestructCalcpidすぐに再び実行されます。

使用Sleep()している呼び出しは、この競合状態を起こりにくくするのに役立ちますが、それをなくすわけではありません。

于 2013-01-11T07:24:02.793 に答える
1

最初に簡潔にするためにコードを短くしましょう。

FinCalcpidUpdatestruct = CreateEvent (NULL, FALSE, FALSE, TEXT("FinCalcpidUpdatestruct"));
FinUpdatestructCalcpid = CreateEvent (NULL, FALSE, TRUE, TEXT ("FinUpdatestructCalcpid"));

void function1()
{
    while(1)
    {
        WaitForSingleObject (FinCalcpidUpdatestruct, INFINITE);
        // Do Something
        SetEvent (FinUpdatestructCalcpid);
        printf(...);
        Sleep(10);
    }
}

void function2()
{
    while(1)
    {
        nGoCode = WaitForSingleObject (FinUpdatestructCalcpid, INFINITE);
        SetEvent (FinCalcpidUpdatestruct);
        printf(...); // **A**
        Sleep(10);
    }
}

基本的に実行の任意の時点で、制御がスレッドから取り除かれ、別のスレッドに渡される可能性があります。ここで、function2既にイベントが設定されており**A**、コードで出力を印刷しようとしているとします。出力が印刷される前に、コントロールが取り除かれ、 に渡されfunction1ます。最後に印刷された出力は既に fromfunction1であり、その待機イベントが設定されているため、フォールスルーしてその内容を再度印刷します。

これが発生すると、出力は時々次のようになります。

function1
function2
function1
function2
function1
// When the situation **A** above happens:
function1
function2
function2
function1
// And we move on as usual further
function2
function1
function2

完了したら、つまり の後にイベントを設定しますprintf。問題ありません。

于 2013-01-11T08:09:18.700 に答える
0

これが私が思うことです...

イベントを設定するまで、ステータスは出力されません。その時点で、何かを出力する前に実行が他のスレッドに切り替わる可能性があります。そのスレッドが最初に実行された場合、1 つのスレッドのループが 2 回実行されたかのように見える場合があります。

しかし、シグナルを受信して​​からイベントを設定するまでの間にグローバル カウンターをインクリメントし、そのカウンターの値をローカル変数に保存すると、おそらく一方のスレッドのカウントが常に奇数で、もう一方のスレッドのカウントが常に偶数であることがわかります (これは、出力が正しくない場合でも)。

于 2013-01-11T03:40:27.573 に答える