- push_back 하면서 capacity가 증가함 하지만 vector 자체는 멀티스레드호환 가능으로 만들어지지 않았음
- 용량이더 큰 것이 추가 되면서 재할당이 될 수 있는데 다른 두개 중 추가하는 스레드 외에 스레드에서 이미 벡터의 메모리를 제거했을 수 있음 재할당으로 => crash
- reserve 20000 을 해 줘도 size 변수를 갱신 할때 문제가 발생 할 수 있음 => 제대로 추가가 되지 않음
- atomic<vector<int32>> 이것도 불가 atomic.load 등의 atomic 자체의 기능을 사용 하는것이기 vector 와 연결(연동)되지 않음
- 어쨌든 문제가 발생 할 수 있음
- 그럼 추가 할때 한번에 한 스레드만 허용가능하도록 lock 처리를 해줘야 함
lock 으로 잠그면 다른 스레드가 접근 불가 unlock 하기 전까지
- 그럼 추가 할때 한번에 한 스레드만 허용가능하도록 lock 처리를 해줘야 함
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <thread>
#include <atomic> //멀티 플랫폼에서 작동 가능
#include <vector>
#include <mutex>
using namespace std;
vector<int32> v;
mutex m; //화장실의 자물쇠 같은것
void push()
{
for (int32 i = 0; i < 10000; ++i)
{
m.lock(); //자물쇠로 잠그고 하나의 스레드만 진입 가능
v.push_back(i);
m.unlock(); //자물쇠 품
}
}
int main()
{
thread t1(push);
thread t2(push);
t1.join();
t2.join();
cout << v.size() << endl;
return 0;
}
하지만 lock 을 쓸때 병합이 너무 심해지면 일반 적인 상황보다는 느려지게 된다
재귀적으로 lock 을 걸면?
불가능 함, 하지만 recursive mutex 로 가능해짐
=> 코드가 복잡해지면 이함수 안에서 다른 함수를 호출 할때 재귀적으로 락을 걸고 싶을 때가 있을 수 있음
문제가 발생 할수 있는 또 다 른 상황
for 문에서
if(i==10)
{
break;
}
로 빠져나올때 unlock() 을 안하면 무한대기 상태가 됨 (Dead lock) 상황이 됨
수동으로 lock, unlock 하는건 실수가 발생 할수 이씩 때문에
RAII (Resource Acqusition Is Initialization)
warp 클래스를 만들어 생성자에서 mutex를 받아 잠그고 소멸자에서 풀어주는 방식으로 사용함
표준적으로 std::lock_guard<> 가 제공 됨
unique_lock 이 존재하는데 lock 하는 시점이 lock_guard 처럼 생성함고 동시에 lock 이 아닌
지연 시켜 lock 을 할 수 있다
The class unique_lock is a general-purpose mutex ownership wrapper allowing deferred locking, time-constrained attempts at locking, recursive locking, transfer of lock ownership, and use with condition variables. The class unique_lock is movable, but not copyable -- it meets the requirements of MoveConstructible and MoveAssignable but not of CopyConstructible or CopyAssignable. The class unique_lock meets the BasicLockable requirements. If Mutex meets the Lockable requirements, unique_lock also meets the Lockable requirements (ex.: can be used in std::lock); if Mutex meets the TimedLockable requirements, unique_lock also meets the TimedLockable requirements. |
"unique_lock과 lock_guard의 차이점은 lock을 걸 수 있는 시점이다. 둘 다 소멸 시점에 lock이 걸려 있다면 unlock을 수행한다. lock_guarud는 lock과 unlock 사이에서 lock과 unlock을 할 수 없지만 unique_lock은 소멸하기 전에 unlock과 lock을 걸 수 있다.
unique_lock은 lock_guard에 기능이 추가된 버전이라고 생각하면 된다."
void push()
{
for (int32 i = 0; i < 10000; ++i)
{
unique_lock<mutex> uniquLock(m, defer_lock); //이때 잠기지 않고
uniquLock.lock(); //이때 mutex 를 잠군다
v.push_back(i);
}
}
결과는 동일하다
20000
ref : https://en.cppreference.com/w/cpp/thread/unique_lock
ref : https://stormpy.tistory.com/277
'운영체제 & 병렬처리 > Multithread' 카테고리의 다른 글
데드락(2) 해결 방안1 (0) | 2022.09.06 |
---|---|
데드락 (1) 원인과 현상 (0) | 2022.09.06 |
[4] #include <atomic> 전역 변수 동기화 문제와 Atomic (0) | 2022.09.06 |
[3] std::thread 와 인자 전달 (0) | 2022.09.06 |
[2] #include <thread> std::thread t(HelloThread); (0) | 2022.09.06 |