12

標準ライブラリのコンテナはスレッドセーフではないという事実を知っています。それによって、私は、たとえばタイプのコンテナには、std::list複数のスレッドが同時にアクセスできないと考えていました(その一部はコンテナを変更する可能性があります)。しかし今では、目に見える以上のものがあるようです。少なくとも私にとっては、もっと微妙なもの、それほど明白ではないもの。

たとえば、最初の引数を値で受け入れるこの関数について考えてみます。

void log(std::string msg, severity s, /*...*/) 
{
   return; //no code!
}

これはスレッドセーフですか?

最初は、関数本体が共有の変更可能なリソースにアクセスしないため、スレッドセーフであるように見えます。したがって、スレッドセーフです。考え直してみると、このような関数を呼び出すstd::stringと、最初の引数である型のオブジェクトが作成されます。このオブジェクトの構築は、内部でを使用するため、スレッドセーフではないと思いますstd::allocator。スレッドセーフではないと思います。したがって、このような関数を呼び出すこともスレッドセーフではありません。しかし、それが正しければ、これはどうでしょうか。

void f()
{
   std::string msg = "message"; //is it thread-safe? it doesn't seem so!
}

私は正しいですか?マルチスレッドプログラムで使用できますかstd::string(または内部で使用するコンテナ)?std::allocator

私は特に、共有オブジェクトではなく、ローカル変数としてのコンテナーについて話しています。

私はグーグルを検索し、具体的な答えがないまま、多くの同様の疑問を見つけました。私は彼と同様の問題に直面しています:

C++03とC++11の両方を検討してください。

4

4 に答える 4

7

C ++ 11では、std::allocatorスレッドセーフです。その定義から:

20.6.9.1/6:備考:ストレージは次のように呼び出すことで取得されます::operator new(std::size_t)

そしての定義から::operator new

18.6.1.4:とのライブラリバージョン、グローバルoperator newoperator deleteのユーザー置換バージョン、operator newおよびoperator deleteC標準ライブラリ関数calloc、、、はmalloc、異なるスレッドからの同時呼び出しの結果としてデータ競合(1.10)を導入してはreallocなりません。free

C ++ 03にはスレッドの概念がなかったため、スレッドセーフは実装固有でした。実装のドキュメントを参照して、実装が提供する保証がある場合はそれを確認する必要があります。Microsoftの実装を使用しているため、このページには、多くのスレッドから同じクラスの複数のコンテナーオブジェクトに安全に書き込むことができると記載されています。これは、std::allocatorスレッドセーフであることを意味します。

于 2012-03-01T18:41:39.160 に答える
5

C ++ 11では、これは次のデフォルトのアロケータで対処されます。

20.6.9.1アロケータメンバー[allocator.members]

デストラクタを除いて、デフォルトのアロケータのメンバー関数は、異なるスレッドからそれらのメンバー関数への同時呼び出しの結果としてデータ競合(1.10)を導入してはなりません。特定のストレージユニットを割り当てまたは割り当て解除するこれらの関数への呼び出しは、単一の全順序で発生し、そのような各割り当て解除呼び出しは、この順序での次の割り当て(存在する場合)の前に発生します。

ユーザー提供のアロケーターは、異なるスレッド間で使用される場合、同じ制約を保持する必要があります。

もちろん、標準の以前のバージョンでは、マルチスレッドについて話していなかったため、これについては何も言われていません。実装がマルチスレッドをサポートする場合(多くまたはほとんどがサポートするように)、それらの問題を処理する責任があります。malloc()ごく最近以前の標準ではそれについて何も述べられていませんでしたが、実装がCおよびC ++にスレッドセーフ(およびその他のライブラリ関数)を提供する方法と同様です。

于 2012-03-01T18:50:51.083 に答える
3

すでに理解しているかもしれませんが、簡単な「はい」または「いいえ」の答えはありません。ただし、これは役立つと思います。

http://www.cs.huji.ac.il/~etsman/Docs/gcc-3.4-base/libstdc++/html/faq/index.html#5_6

私は逐語的に引用します:

5.6 libstdc ++-v3はスレッドセーフですか?

libstdc ++-v3は、次のすべての条件が満たされた場合にスレッドセーフになるように努めます。

システムのlibc自体はスレッドセーフであり、gcc -vは「single」以外のスレッドモデルを報告します。[3.3より前のみ]問題のアーキテクチャには、非ジェネリックなatomicity.hの実装が存在します。

于 2012-03-01T18:52:33.680 に答える
2

std::stringの呼び出し中にanがコピーされるlogと、アロケータスレッドセーフになる可能性があります(C ++ 11では必須)が、コピー自体はそうではありません。したがって、コピーの実行中にソース文字列を変更する別のスレッドがある場合、これはスレッドセーフではありません。

変更前と変更後の半分の文字列で終わる可能性があります。または、コピーがまだ残っている間に変更スレッドが文字列を再割り当て(たとえば、新しい文字を追加することによって)または削除した場合、割り当て解除されたメモリにアクセスすることもあります。行われています。


OTOH、...

std::string msg = "message";

...アロケータがスレッドセーフであれば、スレッドセーフです。

于 2012-03-01T19:53:29.440 に答える