C++11同時多発とマルチスレッドまとめ(六)--condition_variable条件変数


文書ディレクトリ


(一)スレッド概念、作成およびパラメータ伝達(二)排他的反発ロック–mutex,lock_guardyと他のmutex(3)unique_lock置換lock_guardy(四)単一例モード(Singleton)でのスレッドセキュリティ問題(五)window臨界領域(六)condition_variable条件変数(7)std::async非同期タスクとstd::future<>(8)packaged_task<>とpromise<>(九)原子操作atomic<>の概要
(1)概要
  • 通俗的にはスレッドが条件に従ってロックを取り、条件に合致しなければ
  • 休眠すると言われています.
  • スレッドが起動するまで、
  • の競合ロックを継続します.
  • スレッドがスリープ状態に入っていない場合、別のスレッドの起動は無効
  • である.
    (2)使用方法
    1.std::condition_variable条件変数のwait()関数はスレッド2を塞ぐことができる.呼び出しwait()の第1パラメータはstd::unique_lock、第2のパラメータは関数であり、trueを返すと返され、そうでないとスレッドがスリープする.呼び出しnotify_one()スレッドを起動し、スレッドがスリープ状態に入っていない場合は無効です.notify_all()本プログラムは1つの反発量しかないため、すべての効果はoneと同じである.wait中のスレッドが条件を満たすと競合ロック状態に移行し続け、ロックを取得すると実行を継続する.第2のパラメータは、複数のスレッドが同時に起動する後にデータを空にするなど、虚偽の起動を防止するためにlambda式に伝達される.問題:起動後、起動スレッドが競合ロック状態に入ると、8.競合ロックにはwriteのデータが蓄積され、うまく書けないと安定する可能性があります.
  • wait()とnotify()を併用
  • 	void wait<_Predicate>(std::unique_lock<std::mutex> &__lock, _Predicate __p)
    	void wait(std::unique_lock<std::mutex> &__lock)
    
  • wait()は第2のパラメータを入力せず、反発ロックに相当し、条件判定はfalseに戻り続ける.すなわち、毎回他のスレッドnotify()の起動が必要であり、すべての起動スレッドが運転を終了し、スレッド起動がなければ
  • を塞ぐ.
    	condition_variable m_codition; // 
    	std::unique_lock<mutex> myulock(m_mutex);  // lock
    	m_codition.wait(myulock);
    
  • 別のスレッド
  • 	m_codition.notify_one();  // 
    
  • wait()は2つのパラメータを入力し、最初はunique_lock、第2のパラメータはlambda式または他の関数であり、戻り値はブール値
  • でなければならない.
  • が起動するとambda関数がtureに戻ると競合ロック状態に入り、奪われなければ判断を継続し、起動すると実行を継続し、起動後lambda関数がfalseに戻ると
  • を継続する.
    	std::unique_lock<mutex> myulock(m_mutex1);  // lock
    
    	auto lambda = [this]
    	{
    		// 
    		return true;
    	};
    	m_codition.wait(myulock, lambda);
    	//...
    	// 
    	//...
    	myulock.unlock();// 
    
  • notify_all()はwait()内のすべてのスレッドを呼び出し、競合ロック状態に入る.本プログラムは反発量が1つしかないため、すべての効果はoneと同じ
  • である.
  • テストコードセグメント
  • #include 
    #include
    #include
    #include
    
    using namespace std;
    
    class CReadAndWrite
    {
    public:
    	CReadAndWrite() {};
    	void read();
    	void wirte();
    
    private:
    	list<int> m_list;
    	mutex m_mutex1;
    	mutex m_mutex2;
    	condition_variable m_codition; // 
    };
    
    void CReadAndWrite::wirte()
    {
    	for (int i = 0; i < 100; i++)
    	{
    		std::unique_lock<mutex> myulock(m_mutex1);
    
    		m_list.push_back(i);		
    
    		myulock.unlock();
    		m_codition.notify_one();  // 
    
    		cout << "write  " << i << endl;
    	}
    }
    
    void CReadAndWrite::read()
    {
    	for (int i = 0; i < 100; i++)
    	{
    
    			std::unique_lock<mutex> myulock(m_mutex1);  // lock
    
    			auto lambda = [this]
    			{
    				//cout << " ~~~" << endl;
    				return !m_list.empty();
    			};
    			m_codition.wait(myulock, lambda);
    			int num = m_list.front();
    			
    			m_list.pop_front();
    			myulock.unlock();// 
    
    			cout << "  num = " << num << endl;
    	}
    }
    
    
    
    int main()
    {
    
    
    	CReadAndWrite obj;
    	thread mywrite(&CReadAndWrite::wirte, &obj);
    	thread myread(&CReadAndWrite::read, &obj);
    
    	mywrite.join();
    	myread.join();
    
    	std::cout << "Main end!
    "
    ; }