C++11起,标准库除了提供std::async(),这样的高级线程接口以外,还提供了更加简单的std::thread,我们只需要声明一个std::thread对象,然后传递进去函数(function注意这里并不是callable object)进去,以及该function可接受的参数,然后要么等待它结束,要么将他卸离(detach).
如果std::thread想要使用 callable object需要配合std::packaged_task.
我们可以看一下std::thread对传入的function的调用:
template<typename Func, typename ...Types,
typename = typename std::enable_if<
!std::is_member_pointer<typename std::decay<Func>::type>::value,
void>::type>
auto invoke(Func&& func, Types&&... args)->decltype((std::forward<Func>(func))(std::forward<Types>(args)...))
{
return (std::forward<Func>(func))(std::forward<Types>(args)...);
}
首先来看一个例子:
#include <iostream>
#include <thread>
#include <chrono>
#include <random>
#include <exception>
void doSomething(const int& number, const char& c)
{
try {
std::default_random_engine engine(42 * static_cast<int>(c));
std::uniform_int_distribution<int> distribution(10, 100);
for (int i = 0; i < number; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(distribution(engine)));
std::cout.put(c).flush();
}
}catch (const std::exception& e) {
std::cerr << "THREAD-EXCEPTION (thread " << std::this_thread::get_id() << "): " << e.what() << std::endl;
}catch (...) {
std::cerr << "THREAD-EXCEPTION (thread " << std::this_thread::get_id() << ")" << std::endl;
}
}
int main()
{
try {
std::thread t1(doSomething, 5, '.');
std::cout << "- started fg thread " << t1.get_id() << std::endl;
for (int i = 0; i < 5; ++i) {
std::thread temp_thread(doSomething, 10, 'a' + i);
std::cout << "-detach started thread bg thread " << temp_thread.get_id() << std::endl;
temp_thread.detach();
}
std::cin.get();
std::cout << "- join fg thread " << t1.get_id() << std::endl;
t1.join();
}catch (const std::exception& e) {
std::cerr << "EXCEPTION: " << e.what() << std::endl;
}
return 0;
}
std::thread的构造函数:
thread() noexcept;
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
thread (const thread&) = delete;
thread (thread&& x) noexcept;
1,默认构造函数,构建一个没有任何callable object对象的线程.
2,显式构造函数(也就意味着不支持隐式的类型转换),接受一个function以及该function可接受的参数(注意这些参数都是by-value的形式传递进去的,也就是拷贝).
3,被删除了的copy-constructor,也就是说std::thread是不支持copy的.
4,移动构造函数,被移动的std::thread处于无效状态,当前std::thread获得被移动对象的callable object以及callable object可接受的参数.
std::thread::detach
调用该函数使得当前std::thread对象所与母体分离(detach),也就是说使得当前std::thread运行于后台不受任何控制(这样也随之带来一个问题,可能main线程都结束了该线程还在运行).
void detach();
std::thread::get_id
1,如果该std::thread是joinable状态(joinable状态后面会提到),那么就返回一个独一无二的(unique)的当前std::thread的id(std::thread::id).
2,如果该std::thread是not joinable状态,返回std::thread::id();
#include <iostream>
#include <thread>
#include <chrono>
std::thread::id main_thread_id = std::this_thread::get_id();
void is_main_thread()
{
if (main_thread_id == std::this_thread::get_id()) {
std::cout << "main-thread!" << std::endl;
}else {
std::cout << "not main thread! " << std::endl;
}
}
int main()
{
is_main_thread();
std::thread other_thread(is_main_thread);
other_thread.join();
return 0;
}
std::thread::joinable
该函数返回一个bool值:
1,如果当前std::thread对象是default-constructor构造出来的返回false.
2,如果当前std::thread对象被移动到了其他std::thread对象返回false.
3,如果当前std::thread对象的detach()和join()被调用过了返回false.
bool joinable() const noexcept;
std::thread::join
block(阻塞)调用join()的线程,直到std::thread所在的线程完成,与此同时std::thread独显被设置为not joinable.
void join();
std::thread::operator=
std::thread仍然是不支持copy-assign-operator(拷贝赋值运算符),但是支持move-assign-operator.
对于move-assign-operator需要注意的是:
1,当当前std::thread对象处于joinable状态的时候对当前对象调用move-assign-operator,会terminal.
2,如果当前std::thread对象处于not joinable状态那么OK.
thread& operator= (thread&& rhs) noexcept;
thread& operator= (const thread&) = delete;
------------------------------我是分割线----------------------------------
std::this_thread其中的this_thread是位于std这个命名空间中的命名空间.位于该命名空间中有几个函数.这些函数一般都是用来辅助std::thread,std::async.
std::this_thread::get_id
返回一个独一无二的当前线程的ID(一般也就是unsigned int类型).
thread::id get_id() noexcept;
std::this_thread::sleep_for
阻塞(block)正在调用该函数的线程一段时间.
template <class Rep, class Period>
void sleep_for (const chrono::duration<Rep,Period>& rel_time);
std::this_thread::sleep_until
阻塞(block)正在调用该函数的线程直到指定的时间点(timepoint).
template <class Rep, class Period>
void sleep_for (const chrono::duration<Rep,Period>& rel_time);
std::this_thread::yield
这个是个重点,可以参考java和PHP的该函数.
该函数的主要作用是:使正在处于运行状态的该线程,回到可运行状态,以允许其他具有相同优先级的线程获得先执行的机会。但是很有可能该线程刚刚回到可执行状态又被再次执行。
void yield() noexcept;
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
std::atomic<bool> boolean(false);
void doSomething(const int& id)
{
while (!boolean) {
std::this_thread::yield();//注意这里.
}
for (int i = 0; i < 1000000; ++i) {
;
}
std::cout << id;
}
int main()
{
std::thread threads[10];
for (unsigned int i = 0; i < 10; ++i) {
threads[i] = std::thread(doSomething, i);
}
boolean = true;
for (std::thread& ref_thread : threads) {
ref_thread.join();
}
std::cout << '\n';
return 0;
}