C++ thread 基本用法
1.thread类定义
表示各个执行线程的类。一个初始化的线程对象表示活动的执行线程; 这样的线程对象是可连接的,并且具有唯一的线程ID。
缺省构造(未初始化)的线程对象不可join,并且其线程ID对于所有不可join的线程都是通用的。C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。
2.构造函数
转自: https://blog.csdn.net/coolwriter/article/details/79883253
(1).默认构造函数,创建一个空的 thread 执行对象。
(2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
例子:
#include<thread> #include<chrono> using namespace std; void fun1(int n) //初始化构造函数 { cout << "Thread " << n << " executing\n"; n += 10; this_thread::sleep_for(chrono::milliseconds(10)); } void fun2(int & n) //拷贝构造函数 { cout << "Thread " << n << " executing\n"; n += 20; this_thread::sleep_for(chrono::milliseconds(10)); } int main() { int n = 0; thread t1; //t1不是一个thread thread t2(fun1, n + 1); //按照值传递 t2.join(); cout << "n=" << n << '\n'; n = 10; thread t3(fun2, ref(n)); //引用 thread t4(move(t3)); //t4执行t3,t3不是thread t4.join(); cout << "n=" << n << '\n'; return 0; } 运行结果: Thread 1 executing n=0 Thread 10 executing n=30
#include<thread> #include<chrono> using namespace std; void fun1(int n) //初始化构造函数 { cout << "Thread " << n << " executing\n"; n += 10; this_thread::sleep_for(chrono::milliseconds(10)); } void fun2(int & n) //拷贝构造函数 { cout << "Thread " << n << " executing\n"; n += 20; this_thread::sleep_for(chrono::milliseconds(10)); } int main() { int n = 0; thread t1; //t1不是一个thread thread t2(fun1, n + 1); //按照值传递 t2.join(); cout << "n=" << n << '\n'; n = 10; thread t3(fun2, ref(n)); //引用 thread t4(move(t3)); t4.join(); cout << "n=" << n << '\n'; return 0; } 运行结果: Thread 1 executing n=0 Thread 10 executing n=30
其中t3的move,移动构造函数会将 t3
持有的线程句柄转移到 t4
,并将 t3
标记为没有关联任何线程的状态。t3
在移动操作之后变为不可 joinable
的状态,因为它不再持有线程的所有权。试图使用 t3
再进行操作(如 join
或 detach
)将导致未定义行为。
- 原来由
t3
启动的线程会继续执行someFunc
,但现在这个线程的所有权属于t4
。 - 由于线程是在
t3
创建时启动的,移动操作不会重新启动或中断线程,线程继续执行someFunc
,只是现在t4
是它的控制对象。
3.其他成员函数
4.join和detach
可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。用于thread对象的生命周期管理。
在 C++ 中,线程(std::thread
对象)必须在销毁之前被主线程 join
或者设置为 detached
,这是因为如果不这样做,程序可能会出现资源泄漏或者未定义行为。每个 std::thread
对象都会占用一定的系统资源(如线程句柄、堆栈空间等)。如果一个 std::thread
对象在销毁时仍然是 joinable
的,并且没有被 join
或 detach
,这将导致程序的未定义行为。这是因为 C++ 线程库没有明确指定在这种情况下应该执行的操作。
join
: 主线程等待子线程完成执行。当主线程调用子线程的 join
方法时,主线程将阻塞,直到子线程完成。这确保了子线程的资源能够被正确回收。
std::thread t(some_function); t.join(); // 主线程等待 t 线程完成
detach
: 将子线程与主线程分离,让子线程在后台独立运行。当主线程调用子线程的 detach
方法时,子线程将独立执行,主线程不会等待子线程完成。分离的线程在完成后会自动释放其资源。
std::thread t(some_function); t.detach(); // t 线程在后台运行,主线程不再等待
错误用法:
int main() { std::thread t(thread_function); // 未调用 join 或 detach,可能导致未定义行为 return 0; }
当调用 detach
时,线程会自动释放资源,并不会导致资源泄露。分离的线程在其生命周期结束时,由操作系统或线程库负责清理其资源。