static 변수는 함수내에서 한번만 초기화 되는 특징을 가진다. 이는 고유의 값이라는 특징도 가지고 있는데 다중 스레드 내에서 라면 이야기는 달라진다.
여러 스레드 내에서 static
변수가 공유 되길 원한다면 일반적인 static
을 사용하면 된다.
하지만 thread-safe 하지 않다. thread-safe한 변수를 원한다면 std::atomic
을 사용해야 하고,
여기서는 각각의 스레드마다 각기 다른 static변수를 사용하고자 할 때 사용되는 키워드를 소개한다.
#include<iostream>
#include<thread>
void foo() {
static int bar = 0;
printf("%d\n", bar++);
}
int main() {
std::thread th[5];
for (int i = 0; i < 5; i++)
th[i] = std::thread(foo);
for (int i = 0; i < 5; i++)
th[i].join();
return 0;
}
위 코드는 일반적인 static 변수를 사용한 예이다. 결과는 아래처럼...
0
1
2
3
4
가!!!!! 아니라, 이 코드는 버그가 있다. 위와 같은 결과를 원한다면 std::atomic
을 사용했어야 한다.
아래 코드르 버그를 검사해 보라!
#include<iostream>
#include<thread>
#include<vector>
#include<algorithm>
std::vector<bool> bloom;
int* ptr = nullptr;
void foo() {
static int bar = 0;
ptr = &bar;
bloom[bar] = true;
bar++;
}
int main() {
while (1) {
bloom.assign(5, false);
std::thread th[5];
for (int i = 0; i < 5; i++)
th[i] = std::thread(foo);
for (int i = 0; i < 5; i++)
th[i].join();
if (std::any_of(bloom.begin(), bloom.end(), [](bool b)->bool {return !b; })) {
std::cout << "Fail" << std::endl;
}
*ptr = 0;
}
return 0;
}
Fail을 출력하는 모습을 종종 볼 수 있을것이다.
이제 각기 다른 멀티스레드 속에서 각 스레드마다 static 변수를 가지고 싶다면 아래와 같이 한다.
Visual Studio에서는 __declspec(thread)
를 사용하면 되고
gcc에서는 __thread
를 사용하면 된다.
#include<iostream>
#include<thread>
#if defined (_MSC_VER) // Visual studio
#define THREAD_LOCAL __declspec( thread )
#elif defined (__GCC__) // GCC
#define THREAD_LOCAL __thread
#endif
void foo() {
THREAD_LOCAL static int bar = 0;
printf("%d\n", bar++);
}
int main() {
std::thread th[5];
for (int i = 0; i < 5; i++)
th[i] = std::thread(foo);
for (int i = 0; i < 5; i++)
th[i].join();
return 0;
}