CodeNote
Coding Note
CodeNote
전체 방문자
오늘
어제
  • 전체 보기 (35)
    • C++ (33)
      • Modern C++ (12)
      • Modern C++ STL (0)
      • Thread (16)
      • Thread (Async) (5)
    • 디자인패턴 (0)
    • Algorithm (2)
    • Electron (0)
    • Python (0)

블로그 메뉴

  • 홈
  • Github
  • 태그
  • 방명록

공지사항

인기 글

태그

  • LOCK
  • C++
  • 자료구조
  • Free
  • mutex
  • C++ #Memory

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
CodeNote

Coding Note

[Thread] std::call_once
C++/Thread

[Thread] std::call_once

2022. 7. 18. 22:52

std::call_once

std::call_once란 멀티 쓰레드 환경에서 오직 한 번만 호출이 될 수 있도록 한다.

무슨 말인지 예제 코드를 통해 알아본다.

 

Example Code

void print()
{
    std::cout << "printed" << std::endl;
}

void fn()
{
    print();
}

int main()
{
    std::thread t1(fn);
    std::thread t2(fn);
    std::thread t3(fn);
    std::thread t4(fn);
    
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    return 0;
}

출력 결과

thread 4개가 printed라는 문자열을 출력하는 간단한 예제이다. 그런데 만약 이 printed라는 문구를 오직 한 번만 호출하고 싶은 경우 즉, thread가 무수히 많아도 오직 한 번만 호출되게 만들고 싶다면 std::call_once를 사용하면 된다.

 

Example Code : call_once 사용

std::once_flag flag;

void print()
{
    std::cout << "printed" << std::endl;
}

void fn()
{
    // 여러 thread가 생성되더라도 print는 한 번만 호출
    std::call_once(flag, print);
}

int main()
{
    std::thread t1(fn);
    std::thread t2(fn);
    std::thread t3(fn);
    std::thread t4(fn);
    
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    return 0;
}

출력 결과

위와 같이 4개의 thread에서 printed를 출력하였으나 결과에는 한 번만 출력이 되었다.

이러한 동작을 mutex와 boolean 조합으로 만들수도 있으나 이를 사용하면 boolean flag를 사용하기 위해 매 번 mutex를 lock을 하고 해제하는 과정이 필요하다. std::call_once를 사용하면 되는 것을 더 비싼 비용으로 사용하는 것이다. 그러므로 전체 프로세스에서 어떠한 함수를 오직 한 번만 사용한다면 std::call_once가 효율적인 코드를 만들 수 있게 해준다.

 

실제 상황에서 어떻게 사용하는가?

일반적으로는 오브젝트 초기화에 사용한다. 

 

Example Code

class Cat
{
public:
    Cat()
    {
        std::cout << "init cat" << std::endl;
    }
    void speak()
    {
        std::cout << "meow" << std::endl;
    }
};

std::once_flag flag;
std::unique_ptr<Cat> cp = nullptr;

void fn()
{
   std::call_once(flag, []() {
        cp = std::make_unique<Cat>();
   });
}

int main()
{
    std::thread t1(fn);
    std::thread t2(fn);
    std::thread t3(fn);
    std::thread t4(fn);
    
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    cp->speak();

    return 0;
}

출력 결과

Cat 포인터 cp를 한 번만 초기화하고 싶으면 위 코드와 같이 call_once를 사용하면 된다. 위와 같은 경우 여러 thread가 함수 fn을 호출하더라도 cp는 한 번만 초기화가 된다. 즉, call_once는 멀티 쓰레드 환경에서 오브젝트를 한 번만 초기화하는데 사용할 수 있다.

 

조금 더 실제적인 상황을 보자면,

class Zoo
{
private:
    std::optional<Cat> mCat; // C++ 17 optional
    std::once_flag catInitFlag;
}

이와 같이 클래스 내에 한 번만 정의해주기 위해서 std::once_flag도 정의해준 후 사용하면 된다.

'C++ > Thread' 카테고리의 다른 글

[Thread] Condition Variable  (0) 2022.07.23
[Thread] scoped static 초기화  (0) 2022.07.19
[Thread] std::shared_mutex  (0) 2022.07.17
[Thread] Deadlock, std::scoped_lock  (0) 2022.07.17
[Thread] std::unique_lock  (0) 2022.07.17
    'C++/Thread' 카테고리의 다른 글
    • [Thread] Condition Variable
    • [Thread] scoped static 초기화
    • [Thread] std::shared_mutex
    • [Thread] Deadlock, std::scoped_lock
    CodeNote
    CodeNote
    기록 블로그

    티스토리툴바