1、线程的创建
C11创建线程非常简单,只需要提供线程函数就行,标准库提供线程库,并可以指定线程函数的参数。
#include <iostream> #include <thread> void vFunc(int i, int j) { std::cout << i << " " << j << std::endl; } int main() { std::thread t(vFunc, 100, 200); t.join(); return 0; }
2、阻塞&非阻塞
在线程执行的时候,可以选择线程是否阻塞执行,如果阻塞,则主线程等线程函数执行完,再往下执行,否则启动线程之后,主线程直接往下执行。
join函数会阻塞线程,直到线程函数执行结束,如果线程函数有返回值,返回值会被忽略。
如果不希望线程阻塞执行,那就需要线程和线程对象分离,让线程作为后台线程执行,当前线程不会阻塞,但是,分离之后的线程就无法再和主线程发生联系,不能再通过join来等待线程执行完成,线程何时执行完成也无法控制。
需要注意的是,std::thread出了作用域之后将会析构,如果线程函数还未执行完成,则会发生错误,所以,需要保证线程函数的生命周期在线程变量std::thread的生命周期内。
#include <iostream> #include <thread> void vFunc(int i, int j) { std::cout << i << " " << j << std::endl; } int main() { std::thread t(vFunc, 100, 200); t.detach(); //do other thing return 0; }
3、其他用法
3.1 移动
线程不能复制,但是可以移动。移动后的线程不代表任何线程。
#include <iostream> #include <thread> void vFunc(int i) { //do something } int main() { //1.转移 std::thread t(vFunc, 100); std::thread t1(std::move(t)); //t.join(); 将会抛异常 t1.join(); return 0; }
3.2 其他线程函数传入方式
可以通过std::bind或者lambda表达式来创建线程。
//2.lambda&bind std::thread t2(std::bind(vFunc, 100)); std::thread t3([](int a, int b){}, 1, 2); t2.join(); t3.join();
3.3 线程信息获取
线程可以获取当前现成的ID,还可以获取当前CPU的核心数量。
#include <iostream> #include <thread> void vFunc(){} int main() { std::thread t(vFunc); //获取当前线程ID std::cout << t.get_id() << std::endl; //获取CPU核心数量 std::cout << std::thread::hardware_concurrency() << std::endl; return 0; }
3.4 线程休眠
可以通过std::this_thread::sleep_for来让当前函数休眠一段时间。
#include <iostream> #include <thread> #include <chrono> void vFunc() { for (int i = 0; i < 10; i++) { std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << i << std::endl; } } int main() { std::thread t(vFunc); t.join(); return 0; }