[c++] std :: shared_ptr 스레드 안전성 설명

http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html을 읽고 있으며 일부 스레드 안전 문제가 여전히 명확하지 않습니다.

  1. 표준은 참조 카운팅이 스레드로부터 안전하게 처리되고 플랫폼 독립적임을 보장합니다.
  2. 비슷한 문제-표준은 하나의 스레드 (마지막 참조 보유) 만 공유 객체에서 삭제를 호출하도록 보장합니다.
  3. shared_ptr은 그 안에 저장된 객체에 대한 스레드 안전을 보장하지 않습니까?

편집하다:

의사 코드 :

// Thread I
shared_ptr<A> a (new A (1));

// Thread II
shared_ptr<A> b (a);

// Thread III
shared_ptr<A> c (a);

// Thread IV
shared_ptr<A> d (a);

d.reset (new A (10));

스레드 IV에서 reset ()을 호출하면 첫 번째 스레드에서 생성 된 A 클래스의 이전 인스턴스가 삭제되고 새 인스턴스로 대체됩니까? 또한 IV 스레드에서 reset ()을 호출하면 다른 스레드가 새로 생성 된 객체 만 볼 수 있습니까?



답변

다른 사람들이 지적했듯이 원래의 3 가지 질문에 대해 올바르게 파악했습니다.

하지만 편집의 마지막 부분은

스레드 IV에서 reset ()을 호출하면 첫 번째 스레드에서 생성 된 A 클래스의 이전 인스턴스가 삭제되고 새 인스턴스로 대체됩니까? 또한 IV 스레드에서 reset ()을 호출하면 다른 스레드가 새로 생성 된 객체 만 볼 수 있습니까?

부정확하다. 만 d새로운 가리 킵니다 A(10)하고 a, b그리고 c원래의 지점으로 계속됩니다 A(1). 이것은 다음의 짧은 예에서 명확하게 볼 수 있습니다.

#include <memory>
#include <iostream>
using namespace std;

struct A
{
  int a;
  A(int a) : a(a) {}
};

int main(int argc, char **argv)
{
  shared_ptr<A> a(new A(1));
  shared_ptr<A> b(a), c(a), d(a);

  cout << "a: " << a->a << "\tb: " << b->a
     << "\tc: " << c->a << "\td: " << d->a << endl;

  d.reset(new A(10));

  cout << "a: " << a->a << "\tb: " << b->a
     << "\tc: " << c->a << "\td: " << d->a << endl;

  return 0;
}

(분명히, 나는 어떤 스레딩도 신경 쓰지 않았습니다. 그것은 shared_ptr::reset()행동에 영향을 미치지 않습니다 .)

이 코드의 출력은 다음과 같습니다.

a : 1 b : 1 c : 1 d : 1

a : 1 b : 1 c : 1 d : 10


답변

  1. 맞습니다. shared_ptrs는 참조 카운트 값의 원자 적 증가 / 감소를 사용합니다.

  2. 표준은 하나의 스레드 만 공유 객체에서 삭제 연산자를 호출하도록 보장합니다. 공유 포인터의 복사본을 삭제하는 마지막 스레드가 delete를 호출하는 스레드가 될 것임을 구체적으로 지정했는지 확실하지 않습니다 (실제로이 경우 일 가능성이 높습니다).

  3. 그렇지 않습니다. 저장된 객체는 여러 스레드에서 동시에 편집 할 수 있습니다.

편집 : 약간의 후속 조치, 일반적으로 공유 포인터가 작동하는 방식에 대한 아이디어를 얻으려면 http://www.boost.org/doc/libs/1_37_0/boost/shared_ptr.hppboost::shared_ptr 소스를 참조하십시오 .


답변

std::shared_ptr 스레드로부터 안전하지 않습니다.

공유 포인터는 두 개의 포인터 쌍으로, 하나는 객체에 대한 것이고 다른 하나는 제어 블록에 대한 것입니다 (참조 카운터 보유, 약한 포인터에 대한 링크 …).

std :: shared_ptr이 여러 개있을 수 있으며 참조 카운터를 변경하기 위해 제어 블록에 액세스 할 때마다 스레드로부터 안전하지만 그 std::shared_ptr자체는 스레드로부터 안전하거나 원 자성이 아닙니다.

std::shared_ptr다른 스레드가 사용 하는 동안 새 개체를 할당 하면 새 개체 포인터로 끝날 수 있지만 여전히 이전 개체 => CRASH의 제어 블록에 대한 포인터를 사용합니다.


답변