[C++] thread 안에서의 static 변수

spring·2020년 11월 9일
0

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;
}
profile
Researcher & Developer @ NAVER Corp | Designer @ HONGIK Univ.

0개의 댓글