赞
踩
以一个最经典的hellow world作为开始
#include <iostream>
int main()
{
std::cout << "Hello World\n";
}
这是一个单线程,会将“Hello World”写进标准输出流。我们新启动一个线程来显示这个信息
#include <iostream>
#include <thread>
void do_some_work()
{
std::cout<<"Hello Concurrent World\n";
}
int main()
{
std::thread t(do_some_work);
t.join();
}
<thread>
头文件中声明,因此使用 std::thread 时需要包含 <thread>
头文件。#include <iostream> #include <thread> class X { public: void do_work() { std::cout << "Hello World!" << std::endl; } }; int main(int argc, char const *argv[]) { X my_x; std::thread t(&X::do_work, &my_x); t.join(); return 0; }
还可以传递参数:
#include <iostream> #include <thread> class X { public: void do_work(int x) { std::cout << "Hello World!" << x << std::endl; } }; int main(int argc, char const *argv[]) { X my_x; int num(10); std::thread t(&X::do_work, &my_x, num); t.join(); return 0; }
如果参数是引用:
void f2(int& n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 2 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
std::thread t3(f2, std::ref(n)); // pass by reference
注意,传递的参数只能移动,不可以拷贝。
std::thread的入参除了是函数外,还可以是可调用类型(即带有函数调用符类型的实例)
如果需要阻塞等待线程完成,那么需要调用join。比如mythread.join()
join()会在线程完成后,清理线程相关的存储部分,因此:
#include <thread> class thread_guard { std::thread& t; public: explicit thread_guard(std::thread& t_): t(t_) {} ~thread_guard() { if(t.joinable()) { t.join(); } } thread_guard(thread_guard const&)=delete; thread_guard& operator=(thread_guard const&)=delete; };
如果不想等待线程结束(因为需要它们运行在后台),可以分离_(_detaching)线程,从而避免异常安全(exception-safety)问题。不过,这就打破了线程与std::thread对象的对象的联系,即使线程仍然在后台运行着,分离操作也能确保std::terminate()在std::thread对象销毁才被调用。
判断线程是否能够join,可以用joinable
#include <iostream> #include <thread> #include <chrono> using namespace std::chrono_literals; void foo() { std::this_thread::sleep_for(500ms); } int main() { std::cout << std::boolalpha; std::thread t; std::cout << "before starting, joinable: " << t.joinable() << '\n'; t = std::thread{foo}; std::cout << "after starting, joinable: " << t.joinable() << '\n'; t.join(); std::cout << "after joining, joinable: " << t.joinable() << '\n'; t = std::thread{foo}; t.detach(); std::cout << "after detaching, joinable: " << t.joinable() << '\n'; std::this_thread::sleep_for(1500ms); }
std::thread的语义类型std::unique_ptr,可以移动但是不可以拷贝。
除了上面这种方式,线程的所有权还可以在函数外进行转移。比如:
std::thread f() { void some_function(); return std::thread(some_function); } std::thread g() { void some_other_function(int); std::thread t(some_other_function,42); return t; } int test_thread() { std::thread t1=f(); t1.join(); std::thread t2=g(); t2.join(); }
std::thread可以返回,同样的,std::thread也可以作为参数
我们也可以将std::thread放入std::vector中,将这些线程当做一个组:
#include <vector> #include <thread> #include <algorithm> #include <functional> void do_work(unsigned id) {} void f() { std::vector<std::thread> threads; for(unsigned i=0;i<20;++i) { threads.push_back(std::thread(do_work,i)); } std::for_each(threads.begin(),threads.end(), std::mem_fn(&std::thread::join)); } int main() { f(); }
#include <stdio.h> #include <stdlib.h> #include <chrono> // std::chrono::seconds #include <iostream> // std::cout #include <thread> // std::thread, std::this_thread::sleep_for void thread_task(int n) { std::this_thread::sleep_for(std::chrono::seconds(n)); std::cout << "hello thread " << std::this_thread::get_id() << " paused " << n << " seconds" << std::endl; } /* * === FUNCTION ========================================================= * Name: main * Description: program entry routine. * ======================================================================== */ int main(int argc, const char *argv[]) { std::thread threads[5]; std::cout << "Spawning 5 threads...\n"; for (int i = 0; i < 5; i++) { threads[i] = std::thread(thread_task, i + 1); } std::cout << "Done spawning threads! Now wait for them to join\n"; for (auto& t: threads) { t.join(); } std::cout << "All threads joined.\n"; return EXIT_SUCCESS; } /* ---------- end of function main ---------- */
std::thread可以看成是线程的一个容器,一个线程同时只能放在一个容器中。问题是如何知道这个容器中装了那个线程呢?有两种方法:
std::thread::type
默认构造值,这个值表示“无线程”。std::this_thread::get_id()
也可以获得线程标识。线程标识类型为std::thread::id
。std::thread::id
对象可以自由的拷贝和对比
std::thread::id使用场景:
std::thread用于创建一个执行的线程实例,它是一切并发变成的基础,使用时需要包含<thread>
头文件,它提供了很多基本的线程操作:
成员函数名 | 作用 |
---|---|
join | 阻塞等待到该线程结束。 |
detach | 将线程从父进程分离,无法再通过 thread 对象对其进行操作,生命周期也脱离父进程,最终由操作系统进行资源回收。 |
joinable | 检查线程是否可被阻塞等待。 |
get_id | 获取该线程的唯一标识符。 |
swap | 与指定 thread 对象进行互换操作。 |
native_handle | 获取该线程的句柄。 |
hardware_concurrency [static] | 返回逻辑处理器数量。 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。