std::thread t() 提供线程函数或者函数对象
t.join() 阻塞线程直到线程函数执行完毕
t.detach() 如果不希望线程被阻塞执行就调用detach(),但是这会导致线程和线程对象分离。
std::thread创建的线程在出了作用域之后会被析构,如果这时候线程函数还没有执行完的话就会发生错误。
线程不能复制,但是可以移动
std::thread t(func);
std::thread t2(std::move(t));
当move之后,线程对象t就不再代表任何线程了。
线程还可以使用std::bind或者lambda表达式创建线程
std::thread t(std::bind(func, 1, 2));
std::thread t1([](int a, double b){}, 1, 2);
必须注意必须要保证线程函数的生命周期要在线程对象std::thread的生命周期内
获取当前线程id
std::thread t(func);
t.get_id();
线程休眠
std::this_thread::sleep_for(std::chrono::seconds(3));
std::this_thread类保存了当前线程的一些信息参数和方法
std::mutex
std::timed_mutex
std::recursive_mutex
std::recursive_timed_mutex
使用mutex的时候必须lock和unlock成对出现,为了防止有遗忘,这里采用了类似RAII的机制,即在类的构造函数中lock,而在析构函数中去unlock。使用的是lock_guard。
std::mutex g_lock;
std::lock_guard::mutex> locker(g_lock);
那通过以上的代码就不需要担心会忘记unlock这个步骤了,当locker在出作用域的时候会被析构,会自动调用unlock进行解锁的。
递归锁比起非递归锁,效率会低一些。
条件变量需要和互斥量配合起来使用
condition_variable:配合std::unique_lock进行wait操作
condition_variable_any: 和任意带有lock、unlock的mutex都可以搭配使用,比较灵活但是效率比condition_variable差。
std::unique_lock和std::lock_guard的差别在于前者可以自由地释放mutex,而后者必须是在出作用域的时候才能释放。
调用条件变量的wait()方法的时候,会先释放掉互斥量,然后等到被其他线程notify的时候然后再去尝试重新获得mutex。
std::atomic
在多线程环境中,有时候为了保证某个函数只是执行一次的话,可以使用std::call_once()。
std::once_flag flag;
void do_once()
{
std::call_once(flag, [](){/*do something*/});
}
int main()
{
std::thread t(do_once);
std::thread t1(do_once);
t.join();
t1.join();
}
上面的lambda表达式的行为只会执行一次。
主要有std:future, std::promise, std::package_task
std::future作为异步结果的传输通道,可以获取线程函数的返回值
std::future_status status;
do {
status = future.wait_for(std::chrono::seconds(3));
if(status == std::future_status::deferred)
std::cout << "deferred\n";
else if(status == std::future_status::timeout)
/*TODO*/
else if(status == std::future_status::ready)
/*TODO*/
} while(status != std::future_status::ready)
std::promise用来包装一个值,将数据和future绑定起来
std::promise ptr;
std::thread t([](std::promise &p){p.set_value_at_thread_exit(9);}, std::ref(ptr));
std::future f = ptr.get_future();
auto r = f.get();
std::package_task用来包装一个可调用对象,将函数和future绑定起来,以便异步调用。
int func(int x) {return x+2;}
int main()
{
std::package_task<int(int)> tsk(func);
std::future<int> fut = tsk.get_future();
std::thread(std::move(tsk), 2).detach();
int value = fut.get(); //4
vector<std::shared_future<int>> v;
auto f = std::async(std::launch::async, [](int a, int b){return a+b;}, 2, 3);
v.push_back(f);
}
future是不能复制的,不能放到容器里,需要用到shared_future。
async可以用来直接创建异步的task
async(std::launch::async|std::launch::deferred, f, args…)
第一个参数是线程创建的策略,有两种策略:async表示在调用函数的时候立即创建线程,而deferred是延迟加载创建线程,要到调用future.get()或者wait的时候才创建线程。
第二个参数是线程函数
第三个参数是线程函数的参数
std::future<int> f1 = std::async(std::launch::async, [](){return 8;});
cout << f1.get() << endl;
std::future<int> f2 = std::aysnc(std::launch:async, [](){cout << 8 << endl;});
f2.wait();
std::future<int> future = std::async(std::launch::async, [](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::cout << "waiting...\n";
std::future_status status;
do {
status = future.wait_for(std::chrono::seconds(3));
if(status == std::future_status::deferred)
std::cout << "deferred\n";
else if(status == std::future_status::timeout)
/*TODO*/
else if(status == std::future_status::ready)
/*TODO*/
} while(status != std::future_status::ready)
std::cout << future.get() << std::endl;
应该用std::async代替线程的创建
有一次在百度面试过程中被问到future、promise的东西,但是没答上来,之后对这个知识点复习了下。
c++11的future提供了另外一种独特的方式让我们可以和创建的线程进行沟通。
promise这个类会创建空间来保存线程的返回值,然后主线程再去读这个空间就可以。
future实际上是可以理解为指向任务结果的指针,这样子的话那么promise就可以理解为是future和data的封装。
packaged_task是将函数对象和future封装在一起的
async可以同步/异步创建线程,函数的返回值是std::future的,那么就可以得到该线程的运行结果了。
#include
#include
#include
/* This code is for future,promise,packaged_task and async
*/
int main()
{
std::promise<int> prom;
std::thread([](std::promise<int> &p){ std::this_thread::sleep_for(std::chrono::seconds(1));
p.set_value_at_thread_exit(10);}, std::ref(prom)).detach();
std::future<int> f1 = prom.get_future();
std::cout << f1.get() << std::endl;
std::cout << "packaged_task: " << std::endl;
std::packaged_task<int(int)> task(
[](int x)x->int{
std::this_thread::sleep_for(std::chrono::seconds(1));return x+2;});
std::future<int> f2 = task.get_future();
std::thread(std::move(task), 2).detach();
std::cout << f2.get() << std::endl;
std::cout << "async :" << std::endl;
std::future<int> f3 = std::async(std::launch::async, []()->int{
std::this_thread::sleep_for(std::chrono::seconds(1)); return 8;});
std::future_status status;
while(1)
{
status = f3.wait_for(std::chrono::seconds(1));
if(status == std::future_status::ready)
break;
}
std::cout << f3.get() << std::endl;
return 0;
}