あなたが読んでいることは、あなたがそれが意味すると思っていることを意味していません. まず、shared_ptr自体の msdn ページを試してください。
「備考」セクションまで下にスクロールすると、問題の要点が表示されます。基本的に、aは「実」オブジェクトを実際に指しているオブジェクトshared_ptr<>
の数を追跡する方法である「制御ブロック」を指します。shared_ptr<>
したがって、これを行うと:
shared_ptr<int> ptr1 = make_shared<int>();
ここで を介してメモリを割り当てる呼び出しは 1 つしかありmake_shared
ませんが、同じように扱うべきではない 2 つの「論理」ブロックがあります。1 つはint
実際の値を格納するブロックで、もう1 つはshared_ptr<>
それを機能させるすべての「魔法」を格納する制御ブロックです。
スレッドセーフであるのは制御ブロック自体だけです。
強調するために、それを独自の行に入れました。の内容はスレッドセーフではなく、同じインスタンスshared_ptr
への書き込みでもありません。shared_ptr
ここに私が何を意味するかを示すものがあります:
// In main()
shared_ptr<myClass> global_instance = make_shared<myClass>();
// (launch all other threads AFTER global_instance is fully constructed)
//In thread 1
shared_ptr<myClass> local_instance = global_instance;
これは問題ありません。実際、すべてのスレッドで必要なだけこれを行うことができます。そして、local_instance
(スコープ外に出ることによって) が破棄されると、スレッドセーフでもあります。誰かがアクセスできてもglobal_instance
、違いはありません。msdn から取得したスニペットは、基本的に「制御ブロックへのアクセスはスレッドセーフ」であることを意味するためshared_ptr<>
、必要に応じて異なるスレッドで他のインスタンスを作成および破棄できます。
//In thread 1
local_instance = make_shared<myClass>();
これで問題ありません。オブジェクトに影響しますがglobal_instance
、間接的にのみ影響します。それが指す制御ブロックはデクリメントされますが、スレッドセーフな方法で行われます。 local_instance
同じオブジェクト (または制御ブロック) を指すことはなくなりますglobal_instance
。
//In thread 2
global_instance = make_shared<myClass>();
他のスレッドからアクセスされた場合、これはほぼ確実に問題ありませんglobal_instance
(あなたが行っていると言っています)。これを行う場合はglobal_instance
、読み取りだけでなく、どこにでも書き込むため、ロックが必要です。したがって、複数のスレッドからオブジェクトへの書き込みは、ロックによって保護されていない限り、悪いことです。global_instance
したがって、オブジェクトから新しいオブジェクトを割り当てることでオブジェクトから読み取ることはできshared_ptr<>
ますが、書き込むことはできません。
// In thread 3
*global_instance = 3;
int a = *global_instance;
// In thread 4
*global_instance = 7;
の値a
は未定義です。7 かもしれないし、3 かもしれないし、それ以外かもしれません。インスタンスのスレッドセーフは、互いに初期化されたインスタンスのshared_ptr<>
管理にのみ適用され、それらが指しているものには適用されません。shared_ptr<>
私が言いたいことを強調するために、これを見てください:
shared_ptr<int> global_instance = make_shared<int>(0);
void thread_fcn();
int main(int argc, char** argv)
{
thread thread1(thread_fcn);
thread thread2(thread_fcn);
...
thread thread10(thread_fcn);
chrono::milliseconds duration(10000);
this_thread::sleep_for(duration);
return;
}
void thread_fcn()
{
// This is thread-safe and will work fine, though it's useless. Many
// short-lived pointers will be created and destroyed.
for(int i = 0; i < 10000; i++)
{
shared_ptr<int> temp = global_instance;
}
// This is not thread-safe. While all the threads are the same, the
// "final" value of this is almost certainly NOT going to be
// number_of_threads*10000 = 100,000. It'll be something else.
for(int i = 0; i < 10000; i++)
{
*global_instance = *global_instance + 1;
}
}
Aは、複数のスレッドがオブジェクトに正しくアクセスできることを保証するメカニズムではなく、shared_ptr<>
複数のオブジェクト所有者がオブジェクトが破棄されることを保証するメカニズムです。複数のスレッドで安全に使用するには、別の同期メカニズムが必要です ( std::mutexなど)。
IMO について考える最良の方法はshared_ptr<>
、同じメモリを指す複数のコピーがそれ自体の同期の問題を抱えていないことを確認することですが、指しているオブジェクトに対しては何もしません。そのように扱ってください。