원자성

  • 각 쓰레드가 임계영역에서 경쟁(경합)할때, 공유자원에 대한 일관성이 보장되지 않는다.
  • a++의 경우
    • load a
    • a + 1
    • store a
    • 위 과정이 CPU instruction level에서 일어나는데, 이 중간과정에 다른 쓰레드의 instruction이 개입하면 결과의 일관성이 보장되지 않음.

atomic

#include <atomic> 을 통해 통합 원자성 라이브러리를 추가할 수 있다.

int 사용

int sum = 0;

void Add()
{
    for(int i = 0 ; i < 100'0000 < i++){
        sum++;
    }
}

void Sub()
{
    for(int i = 0 ; i < 100'0000 < i++){
        sum--;
    }
}

void main()
{
    std::thread t1(Add);
    std::thread t2(Sub);
    t1.join();
    t2.join();
    cout << sum << endl;
    return 0;
}

실행 결과

-83031

atomic 사용

atomic<int> sum = 0;

void Add()
{
    for(int i = 0 ; i < 100'0000 < i++){
        sum.fetch_add(1);
    }
}

void Sub()
{
    for(int i = 0 ; i < 100'0000 < i++){
        sum.fetch_sub(1);
    }
}

void main()
{
    std::thread t1(Add);
    std::thread t2(Sub);
    t1.join();
    t2.join();
    cout << sum << endl;
    return 0;
}

실행 결과

0
  • atomic의 경우, 일반 int와의 구분을 위해 fetch_add(), fetch_sub()등과 같이 사용하는 것이 좋다.
  • 그냥 sum++을 사용해도 똑같이 동작한다. 내부적으로 오버로딩이 되어있기 때문.