scoped static initialization
c++ concurrency 프로그래밍을 하기 위해서는 꼭 알아야 하는 개념이다.
먼저 scoped static이 무엇인지 코드를 통해 알아본다.
Example Code : scoped static
다음 예제는 단순히 static 변수를 선언하고 있는 함수 fn()을 호출하는 예제이다.
void fn()
{
static int i = 0;
}
int main()
{
fn();
// fn();
// fn();
// fn();
return 0;
}
메모리 접근
위에서 변수 i 는 stack도 아니고 heap도 아닌 static이라는 공간에 저장된다. 이는 static이라는 공간에 저장했기 때문에 프로세스 안에서 오직 하나만 존재한다. 함수 fn을 아무리 반복적으로 부른다고하여도 static 변수 i는 오직 하나인 것이다. 그렇다면 지금은 메인 쓰레드이지만 함수 fn을 여러 쓰레드에서 부른다면 어떻게 될까?
답은 thread가 여러개여도 static 변수인 i는 오직 한 번만 초기화된다. 이를 더 명확하게 보기 위해 Cat 클래스를 정의한 예제를 보자.
Example Code 2 : Class를 사용한 static 변수 선언
class Cat
{
public:
Cat()
{
std::cout << "meow" << std::endl;
}
};
void fn()
{
static Cat cat;
}
int main()
{
std::thread t1(fn);
std::thread t2(fn);
t1.join();
t2.join();
return 0;
}
meow가 한 번만 호출된 것을 확인할 수 있다. 여기에 더해서 scoped static 오브젝트는 lazy initialization된다. 라는 점을 생각해보면 약간 특이하다고 생각할 수 있다. scoped static 오브젝트는 여러 thread가 동시에 해당 함수를 불러도 처음 함수를 부른 그 순간 한번만 초기화가 된다. 이는 C++ standard에서 정의한 것이기 때문에 따로 mutex나 call_once로 보호할 필요가 없다.
참고로 이 기능한 C++ 11(modern C++)부터 추가가 된 것이기 때문에 그 이전 버전에서는 scoped static을 통해 초기화가 한 번만 된다고 보장할 수 없다.
lazy initialization
프로세스 실행 중에 함수 fn이 처음으로 호출이 되었을 때 초기화 된다는 것을 의미한다.
멀티 쓰레드 환경에서 Singleton을 안전하게 초기화하는 방법
scoped static을 통해 thread safe한 싱글톤 클래스를 정의할 수 있다.
Example Code : 멀티 쓰레드 환경에서 Singleton 선언
class Singleton
{
public:
static Singleton& getInstance()
{
static Singleton sObj;
return sObj;
}
};
해당 오브젝트는 오직 한 번만 만들어지므로 thread safe하다고 할 수 있다.
결론은 scoped static을 잘 활용한다면 mutex나 call_once를 굳이 사용할 필요가 없다는 것이다.
'C++ > Thread' 카테고리의 다른 글
[Thread] Producer-Consumer 패턴 (0) | 2022.07.26 |
---|---|
[Thread] Condition Variable (0) | 2022.07.23 |
[Thread] std::call_once (0) | 2022.07.18 |
[Thread] std::shared_mutex (0) | 2022.07.17 |
[Thread] Deadlock, std::scoped_lock (0) | 2022.07.17 |