基本 std::thread 的用法
最简单的 std::thread 范例如下所示,调用 thread 将立即同时开始执行这个新建立的线程,之后 main() 的主线程也会继续执行,基本上这就是一个基本的建立多线程的功能,详细说明请看后面的范例。
#include <iostream>
#include <thread>
void myfunc() {
std::cout << "myfunc\n";
// do something ...
}
int main() {
std::thread t1(myfunc);
t1.join();
return 0;
}
std::thread 常用的成员函数
以下为 c++ std::thread 常用的成员函数
get_id()
: 取得目前的线程 id,回传一个为 std::thread::id 的类型joinable()
: 检查是否可joinjoin()
: 等待线程完成detach()
: 与该线程分离,一旦该线程执行完后它所分配的资源会被释放native_handle()
: 取得平台原生的native handle
其他相关的常用函数有
sleep_for()
: 停止目前线程一段指定的时间yield()
: 暂时放弃CPU一段时间,让给其它线程
范例1. 建立新 thread 执行函数
以下例子为建立新 c++ thread 来执行一个函数,其中 t1 是调用无参数的 foo() 函数,而 t2 线程是调用 bar() 有参数的函数
// g++ std-thread1.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
void foo() {
std::cout << "foo\n";
}
void bar(int x) {
std::cout << "bar\n";
}
int main() {
std::thread t1(foo); // 建立一个新线程且执行 foo 函数
std::thread t2(bar, 0); // 建立一個新线程且执行 bar 函数
std::cout << "main, foo and bar now execute concurrently...\n"; // synchronize threads
std::cout << "sleep 1s\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "join t1\n";
t1.join(); // 等待 t1 线程结束
std::cout << "join t2\n";
t2.join(); // 等待 t2 线程结束
std::cout << "foo and bar completed.\n";
return 0;
}
输出
main, foo and bar now execute concurrently...
foo
bar
sleep 1s
join t1
join t2
foo and bar completed.
注意!在多线程中常常会互相对某函数或变量进行操作,需要对这些进行上锁,下一期将介绍,以确保同一时间只有某一个线程能进行存取
范例2. 建立新 thread 来执行一个类别中的函数
c++ std::thread 的构建可以传入 class 类别中的函数,如下范例所示
AA::start 分别建立 t1、t2 两个线程,而 t1 传入 AA::a1 类别函数,AA::a1 前面记得要加上&,第二参数代表的是哪个类别,之后的参数为传入函数所需的参数
// g++ std-thread2.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
class AA {
public:
void a1() {
std::cout << "a1\n";
}
void a2(int n) {
std::cout << "a2 " << n << "\n";
}
void start() {
std::thread t1(&AA::a1, this);
std::thread t2(&AA::a2, this, 10);
t1.join();
t2.join();
}
};
int main() {
AA a;
a.start();
return 0;
}
输出
a1
a2 10
范例3. 建立新 thread 来执行 lambda expression
std::thread 的构建也可以传入 lambda expression,如下范例所示
auto f = [](int n) {
// Do Something
};
std::thread t1(f, 3);
也可以写成
std::thread t1([](int n) {
// Do Something
};, 3);
范例4. join 等待 thread 执行结束
在 main 主线程建立 t1 线程后,主线程便继续往下执行,如果主线程需要等 t1 执行完毕后才能继续执行的话就需要使用 join,即等待 t1 线程执行完 foo 后主先线程才能继续执行,否则主线程会一直阻塞在 join 这一行
#include <iostream>
#include <thread>
#include <chrono>
void foo() {
this_thread::sleep_for(chrono::milliseconds(200));
cout<<"foo";
}
int main() {
std::thread t1(foo);
cout<<"main 1";
t1.join();
cout<<"main 2";
return 0;
}
范例5. detach 不等待 thread 执行结束
承上例,如果主线程不想等或是可以不用等待 t1 线程的话。就可以使用 detach 来让 t1 线程分离,接着主线程就可以继续执行,t1线程也在继续执行,在整个程序结束前最好养成好习惯确保所有子线程都已执行完毕,因为在 linux 系统如果主线程执行结束还有子线程在执行的话会报错
#include <iostream>
#include <thread>
#include <chrono>
void foo() {
this_thread::sleep_for(chrono::milliseconds(200));
cout<<"foo";
}
int main() {
std::thread t1(foo);
cout<<"main 1";
t1.detach();
cout<<"main 2";
return 0;
}
std::thread 用数组建立多个 thread
// g++ std-thread-array.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
void foo(int n) {
std::cout << "foo() " << n << "\n";
}
int main() {
std::thread threads[3];
for (int i = 0; i < 3; i++) {
threads[i] = std::thread(foo, i);
}
for (int i = 0; i < 3; i++) {
threads[i].join();
}
std::cout << "main() exit.\n";
return 0;
}
输出
foo() 1
foo() 0
foo() 2
main() exit.
std::thread 用 vector 建立多个 thread
// g++ std-thread-vector.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
#include <vector>
void foo(int n) {
std::cout << "foo() " << n << std::endl;
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 3; i++) {
threads.push_back(std::thread(foo, i));
}
for (int i = 0; i < 3; i++) {
threads[i].join();
}
std::cout << "main() exit.\n";
return 0;
}
std::thread 参数传递使用传引用的方法
定义一个myfunc,其参数传递方式为传引用
void myfunc(int& n) {
std::cout << "myfunc n=" << n << "\n";
n+=10;
}
希望建立另外一个线程去执行 myfunc,之后需要取得这个 myfunc 的运算结果,但建立线程时如果写 std::thread t1(myfunc, n);
编译会出现错误,为什么会这样呢?
因为在 std::thread 的参数传递方式为传值,要传参考的话需要透过 std::ref 来辅助达成,所以就会写成这样,myfunc 与 myfunc2 的参数传递方式不同,可以看看这两者之间的差异
// g++ std-thread3.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
void myfunc(int& n) {
std::cout << "myfunc n=" << n << "\n";
n+=10;
}
void myfunc2(int n) {
std::cout << "myfunc n=" << n << "\n";
n+=10;
}
int main() {
int n1 = 5;
std::thread t1(myfunc, std::ref(n1));
t1.join();
std::cout << "main n1=" << n1 << "\n";
int n2 = 5;
std::thread t2(myfunc2, n2);
t2.join();
std::cout << "main n2=" << n2 << "\n";
return 0;
}
输出
myfunc n=5
main n1=15
myfunc n=5
main n2=5
下一期会教大家在多线程中使用 std::mutex进行上锁的用法与范例
std::mutex最全用法归纳