3

次の比較はアトミックアクションですか?つまり、単一のCPU命令に減らすことができますか?

char flag = 2;

for(;;)
{
    if (!flag) // <-- this
        break;

    // sleep
}

これが私がしていることです:

int main()
{
    sf::Mutex Mutex;
    char flag = 2;

    coordinatorFunction(flag);

    for(;;)
    {
        if (!flag)
            break;

        // sleep
    }
}

void workerFunction(void* a)
{
    char* p = static_cast<char*>(a);

    // work

    GlobalMutex.Lock();
    --*p;
    GlobalMutex.Unlock();
}

void coordinatorFunction(char& refFlag)
{
    sf::Thread worker1(&workerFunction, &refFlag);
    sf::Thread worker2(&workerFunction, &refFlag);

    worker1.Launch();
    worker2.Launch();
}
4

8 に答える 8

7

これはそれを回避するための間違った方法です。

メインスレッドはCPUサイクルをできるだけ速く焼き尽くし、flagゼロに達するのを待つだけです。このテストは、最後のテストを除いて、試行されるたびに失敗します。この方法で行う代わりに、スレッドオブジェクトがすべてのワーカーが完了するまでメインスレッドを一時停止させる必要がある可能性が最も高い「結合」機能を使用します。

このように、偶然ではありませんが、テストがアトミックであるかどうかはまったく必要ないため、気にする必要はありません。

于 2011-04-24T19:56:49.993 に答える
2

C ++操作はいずれも、アトミック操作であることが保証されていません。

于 2011-04-24T19:53:10.523 に答える
2

C ++では、アトミックであることが保証されているものはありません。

于 2011-04-24T19:53:30.293 に答える
2

いいえ。私が知る限り、C ++は、アトミックなものとそうでないもの、つまりプラットフォーム固有のものを保証しません。プラットフォームがアトミックに比較できることを保証している場合でも、C++コンパイラがその命令を選択するという保証はありません。

ただし、実際には、char、int、floatなどの単純な値型の比較はアトミックである可能性があります。ただし、コンパイラレベルとプロセッサレベルの両方で、命令の並べ替えの可能性に注意する必要があります。この場合、それは問題ではないかもしれませんが、一般的な場合、それは可能であり、そうです。また、比較がアトミックであっても、comparation-then-branchはアトミックではないことに注意する必要があります。そのため、フラグを使用してアクセスを規制しようとすると、2つのスレッドが両方とも同じコードブロックに入る可能性があります。

適切な保証が必要な場合は、Windowsにはさまざまなインターロック関数があり、 gccにはアトミックビルトインがあります。

于 2011-04-24T19:57:15.890 に答える
1

いいえ、C ++は、操作がアトミックであることを保証しません。あなたの質問のコードは、メモリからレジスタへのロードにコンパイルされる可能性があり、それ自体が複数の命令を取り、その後にテストが続く可能性があります。

于 2011-04-24T19:52:21.117 に答える
1

比較は、それを行うためにいくつかの機械語命令を必要とするため、アトミックではありません(メモリからレジスタにロードするなど)。また、メモリモデルの柔軟性と、テストを実行するスレッドのキャッシュにより、別のスレッドの結果が「表示」されない場合があります。すぐに。

変数が揮発性とマークされている場合は、簡単なテストを実行しても安全かもしれませんが、これはプラットフォーム固有です。他の人が指摘したように、C++自体はこれを保証するものではありません。

于 2011-04-24T19:55:17.563 に答える
1

いいえ

比較には、両方のデータの読み取りと実際の比較の実行が含まれます。データは読み取り命令と比較命令の間で変更される可能性があるため、アトミックではありません。

ただし、同等性を比較しているため、データの置き換えが必要になる場合でも、_InterlockedCompareExchange本能的(x86の命令用)が必要なことを実行する可能性があります。lock cmp xchg

于 2011-04-24T19:55:21.587 に答える
0

あなたが尋ねるべき質問は「--アトミック」ですか?ここで重要なのはそれだけです。フラグが0に達したときに何かをしたい。

このシナリオは気にしません。

1. Main thread reads flag, and it is 1.
2. Worker changes flag with --
3. Main thread doesn't see that flag is actually 0.

1 nsで、メインスレッドがループして再試行するためです。

--はアトミックではなく、2つのスレッドが同時に変更すると、デクリメントがスキップされることに注意してください。

1. Thread A reads flag, flag is 2
2. Thread B reads flag, flag is 2
3. Thread A decrements its copy of flag, 2, and writes to flag, flag is 1
4. Thread B decrements its copy of flag, also 2, and writes to flag, flag is 1.

あなたはデクリメントを失いました。フラグをアトミックにデクリメントする__sync_fetch_and_sub(&flag、1)を使用します 。

最後に、睡眠の周りを回転することはそれを行うための最良の方法ではありません。条件を待つか、シグナルを待つかのどちらかです。フラグを0にデクリメントしたことに気付いたときに、ワーカースレッドに条件またはシグナルを上げさせます。

于 2011-04-27T02:02:39.483 に答える