2

GotWの記事 #45で、Herb は次のように述べています。

void String::AboutToModify(
  size_t n,
  bool   bMarkUnshareable /* = false */
) {
  if( data_->refs > 1 && data_->refs != Unshareable ) {
    /* ... etc. ... */

この if 条件はスレッドセーフではありません。1 つには、"data_->refs > 1" の評価もアトミックではない可能性があります。もしそうなら、スレッド 2 が refs の値を更新している間にスレッド 1 が "data_->refs > 1" を評価しようとすると、data_->refs から読み取られた値は何か - 1、2、または何かになる可能性があります。それは元の値でも新しい値でもありません。

さらに、彼は data_->refs が 1 との比較と Unshareable との比較の間に変更される可能性があることを指摘しています。

さらに下に進むと、解決策が見つかります。

void String::AboutToModify(
  size_t n,
  bool   bMarkUnshareable /* = false */
) {
  int refs = IntAtomicGet( data_->refs );
  if( refs > 1 && refs != Unshareable ) {
    /* ... etc. ...*/

これで、同じ参照が両方の比較に使用され、問題 2 が解決されることがわかりました。しかし、なぜ IntAtomicGet? このトピックに関する検索では何も見つかりませんでした。すべてのアトミック操作は、読み取り、変更、書き込み操作に焦点を当てており、ここでは読み取りのみを行います。それで、私たちはただできるでしょうか...

int refs = data_->refs;

...とにかく、最終的にはおそらく1つの命令に過ぎないのでしょうか?

4

2 に答える 2

1

異なるプラットフォームは、読み取り/書き込み操作の原子性について異なる約束をします。x86たとえば、ダブル ワード ( 4 bytes) の読み取りがアトミック操作になることを保証します。ただし、これがどのアーキテクチャにも当てはまるとは限りませんし、おそらくそうではないでしょう。

異なるプラットフォーム用にコードを移植する予定がある場合、そのような想定によって問題が発生し、コードで奇妙な競合状態が発生する可能性があります。したがって、自分自身を保護し、読み取り/書き込み操作を明示的にアトミックにすることをお勧めします。

于 2015-10-20T21:00:31.013 に答える