Table of Contents
使用C++11让多线程开发变得简单
线程
- 可以通过
std::thread
创建一个线程 - 要让线程函数的生命周期在线程对象的生命周期之内,否则会出错
- 线程对象需要join或detach
- 线程不可以复制但是可以移动(
std::move
) - 几个线程相关的api:
get_id()
获取当前线程idstd::thread::hardware_concurrency()
获取CPU核心数量std::this_thread::sleep_for
让当前线程休眠
互斥量
其实没啥讲的,就是4种语义的互斥量:
std::mutex
std::timed_mutex
std::recursive_mutex
std::recursive_timed_mutex
调用时除了lock
,还可以用try_lock
非阻塞式调用。
条件变量
可以使用condition_varialbe
和condition_variable_any
来实现同步队列。示例代码参考cppreference网站的示例。
条件变量的语义很好理解,故名思义,只是需要注意两点,一是需要注意循环检查predicate是否为true,condition_variable
被唤醒的时候是不保证predicate为true的;二是有一个疑问为什么条件变量非得要和mutex配合使用,答案是为了保护predicate的原子性,可以阅读一下这个答案下的评论:
the mutex is not to protect the condition variable; it is to protect the predicate data, but I think you know that from reading your comment that followed that statement. You can signal a condition variable legally, and fully supported by implementations, post-unlock of the mutex wrapping the predicate, and in fact you’ll will relieve contention in doing so in some cases.
原子变量
std::atomic<T>
,提供以下api:
operator=
is_lock_free
store
load
operator T
exchange
compare_exchange_weak
compare_exchange_strong
对于int这些常见基础类型的原子变量版本,还有相应的特化函数模板实现,具体查cppreference就可以了。
call_once与once_flag
为了保证多线程下某个函数只被调用一次,可以使用call_once
来包裹该函数,同时需要声明一个once_flag
变量。
异步操作类
std::future
future
不支持拷贝,如果需要放进容器里需要使用shared_future
;future
的api:get
、valid
、wait
、wait_for
、wait_until
;std::promise
std::package_task
直接理解这三个概念似乎有点困难,所以可以先看下cppreference给的例子:
#include <iostream>
#include <future>
#include <thread>
int main()
{
// future from a packaged_task
std::packaged_task<int()> task([]{ return 7; }); // wrap the function
std::future<int> f1 = task.get_future(); // get a future
std::thread t(std::move(task)); // launch on a thread
// future from an async()
std::future<int> f2 = std::async(std::launch::async, []{ return 8; });
// future from a promise
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread( [&p]{ p.set_value_at_thread_exit(9); }).detach();
std::cout << "Waiting..." << std::flush;
f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!\nResults are: "
<< f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
t.join();
}
可以看出,future
是用来保存函数的返回值的,package_task
和async
函数都可以返回future
;promise
则是类似于多个线程共享的变量,其他线程通过修改这个共享的变量来返回计算结果,而在promise
内部还是用了future
来保存这个计算结果;package_task
则是可调用对象的包装类,返回一个future
,但package_task
自身不会创建线程,需要借助thread类来运行;async
则是可以创建线程运行函数,并且返回future
。
线程异步操作函数async
函数原型async(std::launch::async|std::launch::deferred, f, args...)
,使用async时会立即创建线程,使用deferred的时候调用future的get/wait方法才创建线程;
近期评论