C ++ 11 thread_local 변수는 자동으로 정적입니까?


85

이 두 코드 세그먼트 사이에 차이점이 있습니까?

void f() {
    thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

void f() {
    static thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

배경 : 원래 STATIC 벡터 V (중간 값을 유지하기 위해 함수에 들어갈 때마다 지워짐)와 단일 스레드 프로그램이 있습니다. 프로그램을 멀티 스레딩 프로그램으로 바꾸고 싶기 때문에 어떻게 든이 정적 수정자를 제거해야합니다. 내 생각은 모든 정적을 thread_local로 바꾸고 다른 것에 대해 걱정하지 않는 것입니까? 이 접근 방식이 역효과를 낼 수 있습니까?


16
thread_local로컬 변수 를 갖는 것은 ...로 시작하는 것은 의미가 없습니다. 각 스레드에는 자체 호출 스택이 있습니다.
Konrad Rudolph 2014

1
여러 C 함수는 원래 정적 또는 전역 변수의 주소를 반환하기 위해 작성되었습니다. 이것은 나중에 다중 스레드 앱 (예 : errno, localtime)에서 사용될 때 모호한 버그를 유발하는 것으로 밝혀졌습니다. 또한, 함수가 여러 스레드에서 호출 될 때 뮤텍스로 공유 변수를 보호하거나 많은 호출 객체와 메소드 사이에 스레드 컨텍스트 객체를 전달해야하는 경우 매우 해로울 수 있습니다. 스레드 해결에 로컬 인 변수 이러한 문제와 기타 문제.
edwinc

3
@Konrad Rudolph 는 각 스레드에 대해 하나의 변수 인스턴스를 초기화하지 static않고 지역 변수만을 선언 static thread_local합니다.
davide

1
@davide 저나 OP의 요점이 아닙니다. 우리는 staticvs 에 대해 말하는 static thread_local것이 아니라 (즉, 자동 저장) 의 C ++ 11 이전 의미를 사용하여 autovs thread_local에 대해 이야기하고 auto있습니다.
Konrad Rudolph

1
또한 스레드 로컬 로컬 정적 변수를 정의하는 방법을 참조하십시오 . . 빠른 언어 변호사 메모 ... Microsoft 및 TLS 지원은 Vista에서 변경되었습니다. 스레드 로컬 스토리지 (TLS)를 참조하십시오 . 변경 사항은 Singleton과 같은 것에 영향을 미치며 적용되거나 적용되지 않을 수 있습니다. abondware 소프트웨어 모델을 사용하고 있다면 아마 괜찮을 것입니다. 여러 컴파일러와 플랫폼을 지원하는 것에 만족한다면주의를 기울여야 할 수도 있습니다.
jww

답변:


92

C ++ 표준에 따름

thread_local이 블록 범위의 변수에 적용될 때 스토리지 클래스 지정자는 정적 명시 적으로 나타나지 않으면 이 내포 됩니다.

따라서이 정의는

void f() {
    thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

다음과 같다

void f() {
    static thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

그러나 정적 변수는 thread_local 변수와 동일 하지 않습니다 .

1 thread_local 키워드로 선언 된 모든 변수에는 스레드 저장 기간이 있습니다. 이러한 엔터티에 대한 스토리지는 해당 엔터티가 생성 된 스레드 기간 동안 지속됩니다. 스레드마다 고유 한 개체 또는 참조가 있으며 선언 된 이름의 사용은 현재 스레드와 관련된 엔터티를 참조합니다.

이러한 변수를 구별하기 위해 표준은 정적 저장 기간과 함께 새로운 용어 스레드 저장 기간 을 도입합니다 .


1
staticextern따라서도 내부 범위 내에서 thread_local 변수에 저장 클래스 만 연결을 의미하지는 않습니다.
Deduplicator

4
@Deduplicator 블록 범위 변수에는 연결이 없습니다. 이력서가 잘못되었습니다. 게시물에서 썼 듯이 스레드 저장 기간이 있습니다. 사실 정적 저장 기간과 동일하지만 각 스레드에 적용됩니다.
모스크바에서 Vlad는

1
extern을 추가하면 정의가 아닌 선언을 수행하는 것입니다. 그래서?
Deduplicator

1
@Deduplicator 따라서 블록 범위 변수의 정의에는 연결이 없음을 의미합니다.
모스크바에서 Vlad는

1
방금 VS 2013에서 시도했는데 "TL 변수는 동적으로 초기화 할 수 없습니다"라고 소리칩니다. 의아해합니다.
v.oddou

19

예, "스레드-로컬 저장소"는 "전역"(또는 "정적 저장소")과 매우 유사하지만 "전체 프로그램 기간"대신 "전체 스레드 기간"이 있습니다. 따라서 블록 로컬 스레드 로컬 변수는 컨트롤이 선언을 처음 통과 할 때 초기화되지만 각 스레드 내에서 개별적으로 스레드가 종료되면 소멸됩니다.


6

와 함께 사용하면 thread_local,static (블라드의 답변 @ 참조) 블록 범위 암시하는 반원 requied; 이름 공간 범위에 대한 연결을 의미합니다.

9.2 / 6 기준 :

클래스 정의 내에서 멤버는 static으로 선언되지 않는 한 thread_local 스토리지 클래스 지정자로 선언되지 않아야합니다.

원래 질문에 답하려면 :

C ++ 11 thread_local 변수는 자동으로 정적입니까?

네임 스페이스 범위 변수를 제외하고는 선택의 여지가 없습니다.

이 두 코드 세그먼트 사이에 차이점이 있습니까?

아니.


4

스레드 로컬 저장소는 정적이지만 단순한 정적 저장소와는 매우 다르게 작동합니다.

변수를 static으로 선언하면 정확히 하나의 변수 인스턴스가 있습니다. 컴파일러 / 런타임 시스템은 정확한시기를 지정하지 않고 실제로 사용하기 전에 언젠가 초기화되도록 보장합니다 (여기에서는 일부 세부 정보 생략).

C ++ 11은이 초기화가 스레드로부터 안전함을 보장하지만 C ++ 11 이전에는이 ​​스레드 안전이 보장되지 않았습니다. 예를 들면

static X * pointer = new X;

둘 이상의 스레드가 동시에 정적 초기화 코드에 도달하면 X 인스턴스가 누출 될 수 있습니다.

변수 스레드 로컬을 선언 할 때 잠재적으로 변수의 많은 인스턴스가 있습니다. 스레드 ID로 색인 된 맵에있는 것으로 생각할 수 있습니다. 즉, 각 스레드는 자체 변수 사본을 볼 수 있습니다.

다시 한 번, 변수가 초기화되면 컴파일러 / 런타임 시스템은 데이터가 사용되기 전에이 초기화가 발생하고 변수를 사용하는 각 스레드에 대해 초기화가 발생하도록 보장합니다. 컴파일러는 또한 시작이 스레드로부터 안전함을 보장합니다.

스레드 안전성 보장은 변수가 예상 한대로 작동하도록 만드는 많은 비하인드 씬 코드가 있음을 의미합니다. 프로그램에 존재하고 이들 중 몇 개가 스레드 로컬 변수에 영향을 미칠지.


@Etherealone : 흥미 롭군요. 어떤 특정 정보? 참조를 제공 할 수 있습니까?
Dale Wilson

1
stackoverflow.com/a/8102145/1576556 . 위키 백과 C ++ 11 기사에서 내가 옳게 기억한다면 그것을 언급합니다.
Etherealone

1
그러나 정적 개체는 먼저 초기화 된 다음 복사본이 할당됩니다. 따라서 스레드로부터 안전한 초기화가 전체 표현식을 포함하는지 여부도 약간 불분명합니다. 그렇지 않으면 스레드로부터 안전한 것으로 간주되지 않기 때문에 아마도 그렇게 할 것입니다.
Etherealone
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.