1、條件變量
線程1完成後,通知其它線程它執行完成了。通過條件變量實現
void CTestThreadCondition::Preparation_Thread()
{
while (true)
{
long ldata = clock();
std::lock_guard<std::mutex> guard(dataMutex_);
if (ldata >= lEndMark - 5000)
{
vsData_.push(ldata);
data_cond_.notify_one();
break;
}
std::this_thread::sleep_for(chrono::milliseconds(1000));
}
}
void CTestThreadCondition::TestCondition()
{
lEndMark = clock() + 15000;
thread thread2(&CTestThreadCondition::Preparation_Thread, this);
thread2.detach();
while (true)
{
std::unique_lock<std::mutex> lk(dataMutex_);
data_cond_.wait(lk, [this]{return !vsData_.empty(); }); // 匿名函數,等待vsData值是否不爲空了
long lPop = vsData_.front();
vsData_.pop();
lk.unlock();
cout << lPop<<endl;
if (lPop >= lEndMark)
{
break;
}
}
}
此處需要使用unique_lock,因爲它裏面支持unlock,lock接口,而條件變量正是利用這兩個接口來實現通知等待的
wait接口需要傳入函數指針,用來判斷接受到信號後事繼續wait還是往下執行,部分wait源碼。收到notify_one後,wait(_Lck)就會往下執行
然後判斷!_Pred(),如果此時該函數還是返回false,那就需要等待下一次的notify_one了。
template<class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
{ // wait for signal and test predicate
while (!_Pred())
wait(_Lck);
}
wait(_Lck)中會先將lk執行unlock。wait成功接受會,再將其lock。此時如果有其它線程(比如notify_one後它的lk未執行unlock)佔用這把鎖,也是無法繼續往下執行的
條件變量時和信號量一起使用的,需要注意它對信號量的一些操作和改變,它依賴於信號量
notify_all是通知所有等待該信號的wait方法,notify_one是通知某一個,儘量一個信號一個等待。notify_all後信號量還是隻能一個鎖定
2、future
接受到線程的返回值
int Accumute(int i)
{
Sleep(3000);
return i;
}
void CTestThreadCondition::TestFutureGet()
{
// async的構造函數接受的是一個右值引用&&
// 第一個參數可以不傳,不傳與傳入async目前看來是一樣的,都表示在一個新的線程中立刻運行Accumute
std::future<int> the_answer1 = std::async(std::launch::async, Accumute, 10);
the_answer1.wait(); // wait會堵塞,直到the_answer1的線程執行返回結果
int iRet1 = the_answer1.get(); // wait堵塞完後,get中存儲的該值。如果不適用wait直接用get也是一樣的會堵塞直到返回值
std::future<int> the_answer2 = std::async(Accumute, 20); // 與上面一樣
Sleep(4000);
the_answer2.wait();
int iRet2 = the_answer2.get();
// 傳入deferred,表示不立刻運行,等到future調用wait或則get時纔開始運行
// wait表示等待線程運行完成,get是獲取結果,也可以不調用wait,直接調用get也會進行等待線程執行完成的
std::future<int> the_answer3 = std::async(std::launch::deferred, Accumute, 30);
Sleep(4000);
the_answer3.wait();
int iRet3 = the_answer3.get();
}
3、packaged_task
將任務打包
void CTestThreadCondition::gui_thread()
{
while (true)
{
packaged_task<int(int)> task; // 當前待處理的任務
{
lock_guard<mutex> lock(taskMutex_);
if (Tasks_.empty())
{
Sleep(10);
continue;
}
task = std::move(Tasks_.front());
Tasks_.pop_front();
}
task(10); // 參數如何傳遞???
}
}
void CTestThreadCondition::TestFuturePackaged()
{
thread thread1(&CTestThreadCondition::gui_thread, this);
// 將任務放到一個隊列中,然後線程不斷從隊列中取值進行執行
packaged_task<int(int)> task(Accumute); // 將函數指針放到一個packaged_task中,支持通過task轉換成future,也可以直接執行task
future<int> res = task.get_future();
// task(1); // 也可以直接調用,然後res去get,此時會堵塞。task就是直接調用函數了
{
lock_guard<mutex> lock(taskMutex_);
Tasks_.push_back(std::move(task)); // 放到隊列中,在其它線程取值
}
int iRet = res.get();
thread1.join();
}
4、Promise
void CTestThreadCondition::TestFuturePromise()
{
std::promise<int> PromiseTask;
PromiseTask.set_value(Accumute(10)); // setvalue就開始執行Accumute了?
future<int> futureTask = PromiseTask.get_future();
int aa = futureTask.get();
// 多次get會崩潰
//int aa2 = futureTask.get();
}
5、shared_future
多個線程等待future的值
void CTestThreadCondition::TestSharedFuture()
{
// future只能等待一個future。如果多個線程都想要得到future的值,多次get會崩潰。這是故意這樣設計的。爲了統一異步結果的所有權
// 此時需要使用shared_future
promise<int> p1;
future<int> f(p1.get_future());
assert(f.valid());
shared_future<int> sf(std::move(f));
// 也可以直接通過future的shared接口直接轉移所有權
//shared_future<int> sf = f.share();
assert(!f.valid());
assert(sf.valid());
}
6、時鐘
chrono標準庫中部分接口,代替windows中sleep接口的方法:this_thread::sleep_for
sleep_for表示等待多少時間,sleep_unit表示等待到某個時間點。其它接口_for,_unit也是一樣的。
void CTestThreadCondition::TestTime()
{
chrono::system_clock::time_point tmNow = chrono::system_clock::now();
future<int> f = async(Accumute, 10);
if (f.wait_for(std::chrono::microseconds(4*1000*1000)) == future_status::ready) // microseconds是微秒
{
cout<< "f.get()"<<f.get()<<endl;
}
future<int> f2 = async(Accumute, 10);
if (f2.wait_until(chrono::steady_clock::now() + chrono::milliseconds(4000)) == future_status::ready) // milliseconds是毫秒
{
cout << "f2.get()" << f2.get() << endl;
}
}
this_thread::sleep_for/sleep_until
conditon_variable::wait_for/wait_until
conditon_variable_any::wait_for/wait_until
time_mutex::try_lock_for/try_lock_until
recursive_time_mutex::try_lock_for/try_lock_unitl
unique_lock<timeLockable>::unique_lock/unique_lock(lockable,time_point/duration)
future<valuetype>::wait_for/wait_until
shared_future<valuetype>::wait_for/wait_until