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