#include <iostream>
#include <atomic>
#include <thread>
#include <mutex>
std::mutex m;
bool use_flag = false;
void work()
{
//m.lock();
// mutex를 쓰지말고 bool을 이용할순 없을까? -> busy waiting(혹은 spin-lock)
// busy waiting
// sleep을 하지않고 루프를 돌면서 대기
// CPU자원을 계속 낭비하기에 일반적으로 좋지는 않음
// 단, 공유자원을 참조하는시간이 지극히 작을경우 오히려 좋음.(lock보다 빠름)
while(use_flag);
usg_flag = true; // 사용중
std::cout << "start. using shared resource" << std::endl;
std::cout << "end. using shared resource" << std::endl;
usg_flag = false; // 이게 멀티스레드에 세이프할까? -> 느낌상 세이프지 않음
//m.unlock();
}
int main()
{
std::jthread t1(work), t2(work);
}
해결해보자
std::atomic_flag
를 이용할 예정이고- 동작은
std::atomic<bool>
과 거의 유사한데 - lock-free(CPU 명령에서 동기화 지원)을 지원하고
- 최소의 멤버함수를 제공하기에 실수가 적다(store, load없음)
- 동작은
#include <iostream>
#include <atomic>
#include <thread>
// std::atomic_flag flag = ATOMIC_FLAG_INIT;
// C++20이후에는 초기화를 굳이 하지않아도 됨
std::atomic_flag flag; // false로 초기화 된다.
void work()
{
while(flag.test_and_set());
usg_flag = true;
std::cout << "start. using shared resource" << std::endl;
std::cout << "end. using shared resource" << std::endl;
flag.clear(); // flag = false
}
int main()
{
std::jthread t1(work), t2(work);
}
Example
#include <iostream>
#include <atomic>
#include <thread>
class spinlock
{
std::atomic_flag flag;
public:
void lock() {while(flag.test_and_set());}
void unlock() {flag.clear();}
};
spinlock spin;
void work()
{
spin.lock();
std::cout << "start. using shared resource" << std::endl;
std::cout << "end. using shared resource" << std::endl;
spin.unlock();
}
atomic_ref(C++20)
#include <iostream>
#include <atomic>
#include <thread>
struct Machine
{
int data{0};
int count{0};
};
Machine m;
void foo()
{
// 레퍼런스처럼 동작하지만 아토믹
std::atomic_ref<int> cnt{m.count};
for(int i = 0; i < 1000000; i++)
{
//++(m.count);
++cnt;
}
}
int main()
{
{
std::jthread t1(foo), t2(foo), t3(foo);
}
std::cout << m.count << std::endl;
}