• push_back 하면서 capacity가 증가함 하지만 vector 자체는 멀티스레드호환 가능으로 만들어지지 않았음
  • 용량이더 큰 것이 추가 되면서 재할당이 될 수 있는데 다른 두개 중 추가하는 스레드 외에 스레드에서 이미 벡터의 메모리를 제거했을 수 있음 재할당으로 => crash
  • reserve 20000 을 해 줘도 size 변수를 갱신 할때 문제가 발생 할 수 있음 => 제대로 추가가 되지 않음
  • atomic<vector<int32>> 이것도 불가 atomic.load 등의 atomic 자체의 기능을 사용 하는것이기 vector 와 연결(연동)되지 않음
  • 어쨌든 문제가 발생 할 수 있음
    • 그럼 추가 할때 한번에 한 스레드만 허용가능하도록 lock 처리를 해줘야 함
      lock 으로 잠그면 다른 스레드가 접근 불가 unlock 하기 전까지

 

 

#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

 

반응형

+ Recent posts