스레드 동기화
#include <iostream>
#include <thread>
#include <chrono>
#include <string_view>
using namespace std::literals;
void delay() { std::this_thread::sleep_for(20ms); }
void foo(std::string_view name)
{
    int x = 0;          // 지역변수는 스레드에 안전!
    static int x = 0;   // 전역변수라면? 스레드에 안전하지 못하다
    for(int i = 0; i < 10; i++)
    {
        x = 100; delay();
        x = x + 1; delay();
        std::cout << name << " : " << x << std::endl; delay();
    }
}
int main()
{
    std::thread t1(foo, "A");
    std::thread t2(foo, "\tB");
    t1.join();
    t2.join();
}
std::mutex m;
// ...
void foo(std::string_view name)
{
    static int x = 0;
    for(int i = 0; i < 10; i++)
    {
        m.lock();
        x = 100; delay();
        x = x + 1; delay();
        std::cout << name << " : " << x << std::endl; delay();
        m.unlock();
    }
}
// ...
mutex 상세
- mutex종류 
std::mutexstd::timed_mutexstd::recursive_mutexstd::recursive_timed_mutexstd::shared_mutex(C++17)std::shared_timed_mutex(C++17)
 
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std::literals;
std::mutex m;
int share_data = 0;
void foo()
{
    if(m.try_lock())
    {
        share_data = 100;
        stds::cout << "using shared_data" << std::endl;
        m.unlock();
    }
    else
    {
        stds::cout << "mutex획득실패" << std::endl;
    }
}
int main()
{
    std::thread t1(foo);
    std::thread t2(foo);
    t1.join();
    t2.join();
    // OS에서 사용중인 mutex 핸들을 리턴
    std::mutex::native_handle_type h = m.native_handle();
    std::mutex m2 = m;  // Error - 복사생성이 안됨, Move도 안됨
}
mutex Vs timed_mutex
- timed_mutex : 
try_lock_for,try_lock_until을 지원한다 
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std::literals;
std::timed_mutex m;
int share_data = 0;
void foo()
{
    if(m.try_lock_for(2s))
    {
        share_data = 100;
        stds::cout << "using shared_data" << std::endl;
        m.unlock();
    }
    else
    {
        stds::cout << "mutex획득실패" << std::endl;
    }
}
int main()
{
    std::thread t1(foo);
    std::thread t2(foo);
    t1.join();
    t2.join();
}
recursive_mutex
// ...
std::mutex m;
int share_data = 0;
void foo()
{
    m.lock();
    m.lock();   // Error - 다시 lock할순 없다 -> recursive_mutex이용
    // ...
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std::literals;
std::recursive_mutex m;
int share_data = 0;
void foo()
{
    m.lock();
    m.lock();   // 내부적으로 소유횟수를 관리함을 기억
    share_data = 100;
    stds::cout << "using shared_data" << std::endl;
    m.unlock(); // 다른 thread가 접근하지못함, 한 번더 unlock해야한다
}
int main()
{
    std::thread t1(foo);
    std::thread t2(foo);
    t1.join();
    t2.join();
}
Example
class Machine
{
    int shared_data = 0;
    std::recursive_mutex m;
public:
    void f1()
    {
        m.lock();
        shared_data = 100;
        m.unlock();
    }
    void f2()
    {
        m.lock();
        shared_data = 200;
        f1();
        m.unlock();
    }
};
shared_mutex
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <string_view>
using namespace std::literals;
std::mutex m;
int share_data = 0;
void Writer()
{
    while(1)
    {
        m.lock();
        share_data = share_data + 1;
        std::cout << "Writer : " << share_data << std::endl;
        std::this_thread::sleep_for(1s);
        m.unlock();
        std::this_thread::sleep_for(10ms);
    }
}
void Reader(std::string_view name)
{
    while(1)
    {
        m.lock();
        std::cout << "Reader(" << name << ") : " << share_data << std::endl;
        std::this_thread::sleep_for(500ms);
        m.unlock();
        std::this_thread::sleep_for(10ms);
    }
}
int main()
{
    std::thread t1(Writer);
    std::thread t2(Reader, "A");
    std::thread t3(Reader, "B");
    std::thread t4(Reader, "C");
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    // 여기서 생각해 봐야할 문제는 쓰는동안에 읽는건 문제가 될 수 있지만
    // 다른 스레드에서 읽는동안에 같이 읽는건 문제될게 없지 않나??
    // 개선해보자
}
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <string_view>
using namespace std::literals;
std::shared_mutex m;
int share_data = 0;
void Writer()
{
    while(1)
    {
        m.lock();
        share_data = share_data + 1;
        std::cout << "Writer : " << share_data << std::endl;
        std::this_thread::sleep_for(1s);
        m.unlock();
        std::this_thread::sleep_for(10ms);
    }
}
void Reader(std::string_view name)
{
    while(1)
    {
        m.lock_shared();
        std::cout << "Reader(" << name << ") : " << share_data << std::endl;
        std::this_thread::sleep_for(500ms);
        m.unlock_shared();
        std::this_thread::sleep_for(10ms);
    }
}
int main()
{
    std::thread t1(Writer);
    std::thread t2(Reader, "A");
    std::thread t3(Reader, "B");
    std::thread t4(Reader, "C");
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}