-2

このように実装しても安全ですか?:

typedef shared_ptr<Foo>  FooPtr;    
FooPtr                  *gPtrToFooPtr    // global variable

// init (before any thread has been created)
void init()
{
    gPtrToFooPtr = new FooPtr(new Foo);
}

// thread A, B, C, ..., K
// Once thread Z execute read_and_drop(), 
// no more call to read() from any thread.
// But it is possible even after read_and_drop() has returned,
// some thread is still in read() function.
void read()
{
    FooPtr a = *gPtrToFooPtr;
    // do useful things (read only)
}

// thread Z (executed once)
void read_and_drop()
{
    FooPtr b = *gPtrToFooPtr;
    // do useful things with a (read only)
    b.reset();
}

どのスレッドが実際の解放を行うかはわかりません。ブーストshared_ptrはこのような状況で安全にリリースしますか?

Boostのドキュメントによると、スレッドセーフshared_ptrは次のとおりです。

インスタンスは、複数のshared_ptrスレッドによって同時に「読み取り」(const操作のみを使用してアクセス)できます。複数のスレッドによって同時に、さまざま shared_ptr なインスタンスに「書き込み」(演算子=やなどの可変操作を使用してアクセス)することができます。reset

私に関する限り、上記のコードは、上記のスレッドセーフ基準のいずれにも違反していません。そして、私はコードがうまく動くはずだと信じています。私が正しいか間違っているか誰かに教えてもらえますか?

前もって感謝します。


編集済み2012-06-2001:00UTC + 9

上記の擬似コードは正常に機能します。実装はshared_ptr、複数のスレッドがそのインスタンスにアクセスしている状況で正しく機能することを保証します(各スレッドは、コピーコンストラクターを使用してインスタンス化された独自のインスタンスにアクセスする必要があります)。shared_ptr

上記の擬似コードでdelete gPtrToFooPtrは、shared_ptr実装が所有するオブジェクトを最終的にリリース(参照カウントを1つ落とす)する必要があることに注意してください(これはではないので適切な式ではありませんがauto_ptr、誰が気にします;))。この場合、マルチスレッドアプリケーションでSIGSEGVが発生する可能性があることに注意する必要があります。

4

3 に答える 3

1

あなた自身の利益のために、私は正直になります。

あなたのコードは多くのことを行っていますが、ほとんどすべてが役に立たず、ばかげています。

typedef shared_ptr<Foo>  FooPtr;    
FooPtr                  *gPtrToFooPtr    // global variable

スマート ポインターへの生のポインターは、自動リソース管理の利点を無効にし、問題を解決しません。

void read()
{
    FooPtr a = *gPtrToFooPtr;
    // do useful things (read only)
}

a意味のある意味で使用されていません。

{
    FooPtr b = ...
    b.reset();
}

b.reset()ここでは役に立たない、bとにかく破壊されようとしています。bこの機能には何の目的もありません。

何をしているのか、スマート ポインターの目的、 の使用方法shared_ptr、MT プログラミングの方法がわからないのではないでしょうか。そのため、問題を解決しないために、この無駄な機能のばかげた山になってしまいます。

単純なことを単純に行うのはどうですか:

Foo f;

// called before others functions 
void init() {
    // prepare f
}

// called in many threads {R1, R2, ... Rn} in parallel
void read()
{
    // use f (read-only)
}

// called after all threads {R1, R2, ... Rn} have terminated
void read_and_drop()
{
    // reset f
}

read_and_drop() 他のスレッドが を読み取っていないことを保証する前に呼び出しfてはなりません。

于 2012-07-26T12:40:25.283 に答える
1

ここで「安全」をどのように定義しますか? 「オブジェクトが確実に 1 回破棄されるようにしたい」と定義した場合、はい、リリースは安全です。ただし、問題は、この例では 2 つのスレッドが 1 つのスマート ポインターを共有していることです。これはまったく安全ではありません。1 つのreset()スレッドによって実行された は、他のスレッドには表示されない場合があります。

ドキュメントで述べられているように、スマート ポインターは組み込み型 (ポインター) と同じ保証を提供します。したがって、他のスレッドがまだ読み取りを行っている可能性があるときに、保護されていない書き込みを実行すると問題が発生します。他の読み取りスレッドが他のスレッドの書き込みをいつ確認するかは未定義です。したがって、shared_ptr インスタンス自体が共有されているため、一方のスレッドがポインターを呼び出しreset()ている間、もう一方のスレッドではポインターがリセットされない可能性があります。

ある種のスレッド セーフが必要な場合は、2 つの共有ポインター インスタンスを使用する必要があります。もちろん、そのうちの 1 つをリセットしてもオブジェクトは解放されません。もう 1 つのスレッドがまだそのオブジェクトへの参照を持っているからです。通常、この動作は意図されています。

ただし、より大きな問題は、shared_ptrs を誤用していることだと思います。shared_ptrs のポインターを使用し、(new を使用して) ヒープに shared_ptr を割り当てることは非常にまれです。これを行うと、スマート ポインターの使用を回避したいという問題が発生します (ここで、shared_ptr の有効期間を管理する必要があります)。最初に、スマート ポインターとその使用法に関するサンプル コードを確認してください。

于 2012-06-18T17:14:14.020 に答える
-1

あなたの編集に:

reset()グローバルで最初に呼び出さないのはなぜshared_ptrですか?

  • あなたがオブジェクトに最後にアクセスした場合、それは削除されます。その後shared_ptr、ヒープ上の を削除します。
  • 他のスレッドがまだそれを使用している場合は、ref カウントを 1 つ減らし、参照先の (まだ存在する) オブジェクトからグローバル ptr を「切断」します。shared_ptrその後、まだ使用している可能性のあるスレッドに影響を与えることなく、ヒープ上のを安全に削除できます。
于 2012-06-20T12:27:45.193 に答える