인프런 커뮤니티 질문&답변

태상규님의 프로필 이미지

작성한 질문수

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

condition_variable 파트 질문입니다.

해결된 질문

22.02.06 23:39 작성

·

141

1

강사님 제가 이해한 부분이 맞는지 궁금합니다.
 
제가 처음에 이해한 부분입니다.
1. Consumer에서 먼저 잡은 lock을 한 경우 unlock 후 대기, Producer에서 lock을 하고 push한 후, cv.notify_one()을 실행한다.
2. Consumer에서 먼저 잡은 경우는 cv.wait()에서 lock을 걸고 진행하고, 늦게 잡은 경우도 unique_lock에서 lock을 건다.
3. Consumer에서 끝나면 Producer는 이미 계속 lock을 걸려고 하고 있으므로, 1, 2번을 반복한다.
 
위의 경우라면 큐의 사이즈가 0 1 0 1 0 1...이 반복되서 결과 값이 0 0 0 0... 이 된다고 생각했습니다. 하지만 결과 값은 확 늘었다가 1씩 줄어들다가 또 확 늘었다가 1씩 줄어들다를 반복하였습니다.(결과적으로 몇천, 몇만, 몇십만까지 증가하였습니다.)
 
코드의 첫 번째 주석대로 Producer를 기준으로 큐의 사이즈 값을 출력하니 0 0 0 0... 까지는 아니지만 모든 수가 4미만으로 나옵니다.
 
Producer에서 lock을 해제할 경우 Consumer에서 접근이 가능하지만 조건이 걸려있어 0미만으로는 가지 않을 것이고, Consumer에서 lock을 해제할 경우 Producer에서 여러 번 값을 넣는 경우라면 이해는 갑니다.
 
위 경우를 생각하여 Producer에게 sleep_for 함수를 적용해서 코드의 두 번째 주석을 넣고 실행하니 기존 답에서 모든 수가 4미만으로 나왔습니다.
 
말이 길었습니다.. 질문입니다.
제가 이해한 경우가 맞는지 아니면 멀티쓰레드 쪽의 개념이 포괄적으로 이해해야 될까요? 강사님이 말씀하신대로 뇌가 말랑해지기위해 노력중입니다.
mutex m;
queue<int32> q;

condition_variable cv;

void Producer()
{
	while (true)
	{
		{
			unique_lock<mutex> lock(m);
			
			q.push(100);
		}
		cv.notify_one();

		//cout << q.size() << endl;
                //this_thread::sleep_for(0.001ms);
	}
}

void Consumer()
{
	while (true)
	{
		unique_lock<mutex> lock(m);
		
		cv.wait(lock, []() {return q.empty() == false; });

		int32 data = q.front();
		q.pop();
		cout << q.size() << endl;
	}
}

답변 1

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

2022. 02. 07. 00:45

1 01 0 은 아니구요
cv.notify_one()을 한 다음에 친절히 상대방에 꺼내가는 것을 기다리진 않기에 
절묘하게 다음 while(true) 루프에서 또  lock을 먼저 획득하면 
연이어서 숫자가 늘어날 수 있습니다.

멀티쓰레드 환경은 공유자원을 차지하려고 격렬히 경합을 하는 것이죠.
그렇다면 매번 데이터를 produce 하는 쪽만 승리하면 어쩌지? 싶겠지만
이렇게 while (true)로 데이터를 밀어넣는 경우는 현실상에 없어 큰 문제 없습니다.