Atomic Operation
#include <stdio.h>
#include <Windows.h>
#include <process.h>
LONG x = 0; // 모든 스레드 공유
UINT __stdcall foo(void* p)
{
    for(int i = 0 i < 1000000; i++)
    {
        x = x + 1;
    }
    return 0;
}
int main()
{
    HANDLE h1 = (HANDLE)_beginthreadex(0, 0, foo, 0, 0, 0);
    HANDLE h2 = (HANDLE)_beginthreadex(0, 0, foo, 0, 0, 0);
    HANDLE h3 = (HANDLE)_beginthreadex(0, 0, foo, 0, 0, 0);
    HANDLE h[3] = {h1, h2, h3};
    WaitForMultipleObjects(3, h, TRUE, INFINITE);
    printf("result : %d\n", x);
    return 0;
}
UINT __stdcall foo(void* p)
{
    for(int i = 0 i < 1000000; i++)
    {
        // x = x + 1;
        __asm
        {
            mov eax, x  // 1번 thread가 eax로 x값을 가져간 상태에서
            add eax, 1
            mov x, eax  // 2번 thread가 x에 eax에 1을 더한값을 넣는다면? -> 이러한이유로 원하는 값이 안나옴
        }
    }
    return 0;
}
해결책?
UINT __stdcall foo(void* p)
{
    for(int i = 0 i < 1000000; i++)
    {
        // x = x + 1;
        __asm
        {
            inc x       // 이 어셈블리 명령은 어셈블리 명령중 다른 thread가 사용하지 못하게 함.
            // 단, muti CPU를 사용할 경우 물리적으로 CPU가 다르기에 역시 정상적으로 동작하지 않음.
        }
    }
    return 0;
}
UINT __stdcall foo(void* p)
{
    for(int i = 0 i < 1000000; i++)
    {
        // x = x + 1;
        __asm
        {
            lock inc x      // 아에 lock을 걸어야한다.
        }
    }
    return 0;
}
무조건 어셈블리를 써야하나? -> Nope
UINT __stdcall foo(void* p)
{
    for(int i = 0 i < 1000000; i++)
    {
        // x = x + 1;
        InterlockedIncreament(&x);  // 내부적으로 lock inc를 사용
        // (참고) 브레이크 포인트를 여기 걸고 Alt+F8을 누르면, 기게어코드를 보여줌.
    }
    return 0;
}
- Atomic operation 
InterlockedIncreamentInterlockedXXX
 
Thread Local Storage
#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include <process.h>
// 호출할때 마다 3의 배수를 차례대로 반환
int next3times()
{
    static int n = 0;
    n = n + 3;
    return n;
}
UINT __stdcall foo(void* p)
{
    printf("%s : %d\n", next3times());  // 3
    printf("%s : %d\n", next3times());  // 6
    printf("%s : %d\n", next3times());  // 9
    return 0;
}
int main()
{
    HANDLE h1 = (HANDLE)_beginthreadex(0, 0, foo, (void*)"A", 0, 0);
    HANDLE h2 = (HANDLE)_beginthreadex(0, 0, foo, (void*)"\tB", 0, 0);
    getchar();
    return 0;
}
결과는?
    B : 3
    B : 6
    B : 9
A : 3
A : 12
A : 15
매번 이렇진 않지만 어쨋든 예상했던 결과와는 다르게 나온다.
Thread별로 next3times()가 동작하게 해보자(Thread당 data(static) 메모리를 갖게하자) -> Thread Local Storage
int next3times()
{
    // TLS(Thread Local Storage)에 넣어달라
    __declspec(thread) static int n = 0;
    n = n + 3;
    return n;
}
    B : 3
    B : 6
    B : 9
A : 3
A : 6
A : 9
__declspec(thread)는 지역변수에 붙일 수 없다. static전역, 전역변수에만 붙일 수 있음.