c++다 중 스 레 드 는 왜 조건 변 수 를 사용 하 는 지 상세 하 게 설명 합 니 다.

먼저 예시 1 을 보십시오.

#include <iostream>
#include <windows.h>
#include <mutex>
#include<deque>
#include <thread>
using namespace std;


int nmax = 20;
std::deque<int> m_que;
std::mutex mymutex;


//   

void producterex()
{
	int i = 1;
	while (i<nmax)
	{
		//     
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::unique_lock<mutex> lcx(mymutex);
		m_que.push_back(i);
		cout << "producted:" << i << endl;
		lcx.unlock();
		i++;
	}

	cout << "product thread exit
"; } // void consumerex() { int i = 0; while (1) { std::unique_lock<mutex> lcx(mymutex); if (!m_que.empty()) { int i = m_que.back(); m_que.pop_back(); cout << "consumed:" << i << endl; lcx.unlock(); i++; if (i == nmax) { break; } } else { lcx.unlock(); } } cout << "consumerex thread exit
"; } void main() { std::thread t1(producterex); std::thread t2(consumerex); t1.detach(); cout << "hello"; t2.detach(); cout << " world!
"; getchar(); system("pause"); }
결과:


cpu 사용률 이 매우 높다 는 것 을 알 수 있다.높 은 이 유 는 주로 소비자 스 레 드 에 있 습 니 다.대기 열 이 비어 있 을 때 도 실행 해 야 하기 때 문 입 니 다.너무 많은 무공 해 를 해서 CPU 점유 율 이 너무 높 기 때문에 다음 에 개조 하여 비 어 있 을 때 200 밀리초 를 기다 리 게 하 는 것 은 폴 링 간격 주 기 를 확대 하 는 것 과 같 습 니 다.CPU 의 점용 률 을 낮 출 수 있어 야 합 니 다.
다른 것 은 모두 같 기 때문에 여기에 소비자 의 라인 을 붙인다.

//   
void consumerex()
{
	int i = 0;
	while (1)
	{
		std::unique_lock<mutex> lcx(mymutex);
		if (!m_que.empty())
		{
			int i = m_que.back();
			m_que.pop_back();
			cout << "consumed:" << i << endl;
			lcx.unlock();
			i++;
			if (i == nmax)
			{
				
				break;
			}
		}
		else
		{
			lcx.unlock();
			std::this_thread::sleep_for(std::chrono::milliseconds(200));
		}
		
		
	}

	cout << "consumerex thread exit
"; }
결과:

이 를 통 해 알 수 있 듯 이 CPU 점용 률 이 단번에 떨 어 졌 다.
여기 서 어려움 이 있 습 니 다.휴면 시간 간격(즉,폴 링 간격 주기)을 어떻게 정 하 는 지 입 니 다.간격 이 너무 짧 으 면 CPU 자원 을 너무 많이 차지 하고 간격 이 너무 길 면 제때에 응답 하지 못 해 지연 될 수 있 습 니 다.
이 는 조건 변 수 를 도입 하여 이 문 제 를 해결 했다.조건 변 수 는'알림-깨 우기'모델 을 사용 하고 생산 자 는 하나의 데 이 터 를 생산 한 후에 소비자 에 게 사용 하 라 고 알 리 며 소비자 가 통 지 를 받 지 않 기 전에 휴면 상태 에서 CPU 자원 을 절약 하도록 한다.소비자 가 통 지 를 받 은 후에 얼른 휴면 상태 에서 깨 어 나 데 이 터 를 처리 하고 사건 구동 모델 을 사용 하여 일 을 그 르 치지 않도록 하 는 상황 에서 자원 에 대한 소 모 를 최대한 줄 였 다.
condition_variable 소개
C++11 에서 조건 변수(conditionvariable)여러 스 레 드 간 의 동기 화 작업 을 실현 합 니 다.조건 이 만족 하지 않 을 때 관련 스 레 드 는 특정한 조건 이 나타 날 때 까지 계속 막 혀 야 이 스 레 드 들 이 깨 어 날 수 있다.
구성원 함 수 는 다음 과 같 습 니 다.

조건 변 수 는 스 레 드 간 에 공 유 된 전역 변 수 를 이용 하여 동기 화 하 는 메커니즘 으로 주로 두 가지 동작 을 포함한다.
a.하나의 스 레 드 는'조건 변수의 조건 이 성립 되 기 를 기다 리 기 때문에 걸 립 니 다.
b.다른 스 레 드 는'조건 이 성립'되 고 신 호 를 보 내 서 기다 리 는 스 레 드 를 깨 웁 니 다.
경쟁 을 방지 하기 위해 조건 변수의 사용 은 항상 상호 배척 자물쇠 와 결합 된다.일반적인 상황 에서 이 자 물 쇠 는 std:mutex 이 고 이 자 물 쇠 를 관리 하 는 것 은 std::unique 일 수 밖 에 없습니다.lockstd::mutex RAII 템 플 릿 클래스 입 니 다.
위 에서 언급 한 두 가지 절 차 는 다음 과 같은 두 가지 방법 으로 이 루어 진다.
1.대기 조건 성립 시 condition 사용variable 클래스 구성원 wait,waitfor 또는 waituntil。
2.신 호 를 보 내 는 것 은 conditionvariable 클래스 구성원 notifyone 또는 notifyall 함수.
상기 두 가지 유형의 wait 함수 가 모두 막 힐 때 자동 으로 잠 금 권한 을 방출 합 니 다.즉,유 니 크 를 호출 합 니 다.lock 의 구성원 함수 unlock()은 다른 스 레 드 가 자 물 쇠 를 얻 을 수 있 도록 합 니 다.이것 이 바로 조건 변수 와 유 니 크lock 과 함께 사용 하 는 이유 입 니 다.그렇지 않 으 면 현재 스 레 드 가 계속 자 물 쇠 를 차지 하고 스 레 드 가 막 힙 니 다.
거짓 각성
정상 적 인 상황 에서 wait 유형 함수 가 되 돌아 올 때 깨 어 나 거나 시간 이 초과 되 어서 되 돌아 오지 않 으 면==실제 에서 발견 되 기 때문에 운영 체제 의 원인,wait 유형 이 조건 을 만족 시 키 지 못 할 때 되 돌아 와 허위 각성 을 초래 합 니 다.==따라서,우 리 는 일반적으로 서술 어 파 라 메 터 를 가 진 wait 함 수 를 사용 합 니 다.왜냐하면 이러한(xxx,Predicate pred)유형의 함수 가 다음 과 같 기 때 문 입 니 다.

while (!pred()) //while  ,          
{
    wait(lock);
}
원인 설명 은 다음 과 같다.
시스템 에 허위 각성 이 존재 하지 않 는 다 고 가정 할 때 코드 형식 은 다음 과 같다.

if (   xxx  )
{
    //      ,wait        ,         ,    。
    //           ,       ,wait      ,  if  ,
    //        ,    
    wait();  
}


//    
...
올 바른 사용 방식,while 문 구 를 사용 하여 해결:

while (!(xxx  ) )
{
    //      ,  while  ,          ,
    //      ,      
    wait();  
}
//    
....
조건 변 수 를 사용 하 는 상황 을 살 펴 보 겠 습 니 다.

#include <iostream>
#include <windows.h>
#include <mutex>
#include<deque>
#include <thread>
#include<condition_variable>
using namespace std;


int nmax = 10;
std::deque<int> m_que;
std::mutex mymutex;

condition_variable mycv;

//   

void producterex()
{
	int i = 1;
	while (i<nmax)
	{
		//     
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::unique_lock<mutex> lcx(mymutex);
		m_que.push_back(i);
		cout << "producted:" << i << endl;
		lcx.unlock();

		mycv.notify_one();
		i++;
	}

	cout << "product thread exit
"; } // bool m_bflag = false; void consumerex() { int i = 0; bool m_bexit = false; while (!m_bexit) { std::unique_lock<mutex> lcx(mymutex); while (m_que.empty()) { // mycv.wait(lcx); if (m_bflag) { cout << "consumerex thread exit
"; m_bexit = true; break; } } if (m_bexit) { break; } int i = m_que.back(); m_que.pop_back(); lcx.unlock(); cout << "consumed:" << i << endl; } cout << "consumerex thread exit
"; } void main() { std::thread t1(producterex); std::thread t2(consumerex); t1.detach(); cout << "hello"; t2.detach(); cout << " world!
"; mycv.notify_one(); Sleep(15000); m_que.push_back(100); mycv.notify_one(); Sleep(3000); m_bflag = true; mycv.notify_one();// getchar(); system("pause"); }
결과:

mycv.wait(lcx)도 가능 합 니 다.쓰기 방법 을 바 꾸 면 wait()의 두 번 째 매개 변 수 는 하나의 함수 로 검사 조건 을 표시 할 수 있 습 니 다.여 기 는 lambda 함 수 를 사용 하 는 것 이 가장 간단 합 니 다.만약 에 이 함수 가 true 로 돌아 오 면 wait()함수 가 막 히 지 않 고 바로 돌아 갑 니 다.만약 에 이 함수 가 false 로 돌아 오 면 wait()함수 가 깨 어 나 기 를 기다 리 는 것 을 막 을 것 입 니 다.만약 에 위 에서 깨 어 나 면 함수 반환 값 을 계속 판단 할 것 입 니 다.코드 예 시 는 다음 과 같다.

#include <iostream>
#include <windows.h>
#include <mutex>
#include<deque>
#include <thread>
#include<condition_variable>
using namespace std;


int nmax = 10;
std::deque<int> m_que;
std::mutex mymutex;

condition_variable mycv;

//   

void producterex()
{
	int i = 1;
	while (i<nmax)
	{
		//     
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::unique_lock<mutex> lcx(mymutex);
		m_que.push_back(i);
		cout << "producted:" << i << endl;
		lcx.unlock();

		mycv.notify_one();
		i++;
	}

	cout << "product thread exit
"; } // bool m_bflag = false; void consumerex() { int i = 0; while (1) { std::unique_lock<mutex> lcx(mymutex); mycv.wait(lcx, [](){ // false return !m_que.empty(); }); if (m_bflag) { break; } int i = m_que.back(); m_que.pop_back(); lcx.unlock(); cout << "consumed:" << i << endl; } cout << "consumerex thread exit
"; } void main() { std::thread t1(producterex); std::thread t2(consumerex); t1.detach(); cout << "hello"; t2.detach(); cout << " world!
"; mycv.notify_one(); Sleep(15000); m_que.push_back(100); mycv.notify_one(); Sleep(3000); m_bflag = true; m_que.push_back(-1); mycv.notify_one();// getchar(); system("pause"); }

총결산
c++다 중 스 레 드 가 왜 조건 변 수 를 사용 하 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 c+다 중 스 레 드 조건 변수 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기