38

unique_ptrスレッドは安全ですか?以下のコードで同じ数値を2回出力することはできませんか?

#include <memory>
#include <string>
#include <thread>
#include <cstdio>

using namespace std;

int main()
{
    unique_ptr<int> work;

    thread t1([&] {
        while (true) {
            const unique_ptr<int> localWork = move(work);
            if (localWork)
                printf("thread1: %d\n", *localWork);
            this_thread::yield();
        }
    });

    thread t2([&] {
        while (true) {
            const unique_ptr<int> localWork = move(work);
            if (localWork)
                printf("thread2: %d\n", *localWork);
            this_thread::yield();
        }
    });

    for (int i = 0; ; i++) {
        work.reset(new int(i));

        while (work)
            this_thread::yield();
    }

    return 0;
}
4

3 に答える 3

42

unique_ptrは、正しく使用するとスレッドセーフになります。あなたは不文律を破りました:あなたは参照によってスレッド間でunique_ptrを決して渡してはなりません。

unique_ptrの背後にある哲学は、常に1人の(一意の)所有者がいるということです。そのため、同期しなくてもスレッド間でいつでも安全に渡すことができますが、参照ではなく値で渡す必要があります。unique_ptrのエイリアスを作成すると、uniquenessプロパティが失われ、すべての賭けが無効になります。残念ながら、C ++は一意性を保証できないため、忠実に従わなければならないという慣習が残されています。unique_ptrのエイリアスを作成しないでください。

于 2012-07-14T17:30:40.923 に答える
29

いいえ、スレッドセーフではありません。

両方のスレッドがmove明示的な同期なしで作業ポインターを取得する可能性があるため、両方のスレッドが同じ値を取得するか、両方が無効なポインターを取得する可能性があります...これは未定義の動作です。

このようなことを正しく実行したい場合はstd::atomic_exchange、両方のスレッドが正しいセマンティクスで共有作業ポインターを読み取り/変更できるように、おそらく次のようなものを使用する必要があります。

于 2012-07-14T09:37:20.127 に答える
10

Msdnによると:

次のスレッドセーフルールは、標準C ++ライブラリのすべてのクラスに適用されます(以下で説明するshared_ptrクラスとiostreamクラスを除く)。

単一のオブジェクトは、複数のスレッドから読み取るためにスレッドセーフです。たとえば、オブジェクトAが与えられた場合、スレッド1とスレッド2から同時にAを読み取るのは安全です。

単一のオブジェクトが1つのスレッドによって書き込まれている場合、同じスレッドまたは他のスレッドでそのオブジェクトへのすべての読み取りと書き込みを保護する必要があります。たとえば、オブジェクトAが与えられた場合、スレッド1がAに書き込みを行っている場合、スレッド2はAからの読み取りまたはAへの書き込みを禁止する必要があります。

別のスレッドが同じタイプの別のインスタンスに対して読み取りまたは書き込みを行っている場合でも、あるタイプの1つのインスタンスに対して読み取りおよび書き込みを行うのは安全です。たとえば、同じタイプのオブジェクトAとBが与えられた場合、Aがスレッド1で書き込まれ、Bがスレッド2で読み取られている場合は安全です。

于 2012-07-14T09:34:37.947 に答える