C++ 有专门的线程库 它的好处是 我不管在windows Linux unix 还是mac上都可以跑
本质上通过条件编译形成的
1.thread::thread

1. 默认构造(default)
thread() noexcept;
作用:创建一个空的thread对象(不关联任何实际的执行线程)。
特点:
这个对象处于 “未连接(not joinable)” 状态,不能调用join()或detach()。
常用于后续通过移动赋值接收其他线程的所有权(比如配合移动构造)。
2. 初始化构造(initialization )
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
作用:最常用的构造方式 ——创建thread对象的同时,启动一个新线程,执行fn函数(或可调用对象),并传递args作为参数。
关键细节:
Fn是 “可调用对象”:可以是普通函数、lambda 表达式、函数对象、类成员函数(需配合对象指针)等。
explicit:禁止隐式转换(不能用thread t = 某个函数;这种写法,必须显式构造)。
&&+ 完美转发:会将fn和args的参数类型 “原样转发” 给新线程的执行函数,保证效率。
3. 拷贝构造(copy deleted)
thread (const thread&) = delete;
作用:这个构造函数被= delete显式禁用了 ——std::thread不支持拷贝。
原因:线程是 “独占资源”(一个thread对象对应一个实际的系统线程),资源本身无法被复制,因此 C++ 标准直接禁止了拷贝构造。
4. 移动构造(move)
作用:将x对应的线程所有权转移给新创建的thread对象。
特点:
转移后,原对象x会变成 “空的thread对象”(和默认构造的空对象一样,处于 not joinable 状态)。
这是std::thread传递线程所有权的唯一方式(因为不能拷贝)。
2.thread::join
void join();
阻塞调用该函数的线程(通常是主线程),直到被调用的std::thread对象对应的子线程执行完毕。
执行join()后,子线程的资源会被释放,std::thread对象变为不可 joinable状态。
3.thread::joinable
bool joinable() const noexcept; // C++11起,noexcept表示函数不会抛出异常
判断当前std::thread对象是否处于可被join()或detach()的状态,返回值为bool类型:
true:对象关联有效线程,且未被join()/detach()处理,可执行后续操作。
false:对象无关联线程,或已被处理,不可执行join()/detach()。
具体使用方法
void normal_func_with_args(int num, const std::string& str) {
std::cout << "普通函数:" << num << "," << str << std::endl;
}
class Functor {
public:
void operator()(double pi) const {
std::cout << "仿函数:" << pi << std::endl;
}
};
class TestClass {
public:
static void static_member_func(const std::string& tip) {
std::cout << "静态成员函数:" << tip << std::endl;
}
void non_static_member_func(const std::string& msg) {
std::cout << "非静态成员函数:" << msg << std::endl;
}
};
int main() {
std::thread t_empty;
std::cout << "t_empty可join:" << std::boolalpha << t_empty.joinable() << std::endl;
std::thread t2(normal_func_with_args, 100, "Hello Thread");
std::thread t5(Functor(), 3.1415926);
std::thread t6(&TestClass::static_member_func, "静态函数传参");
TestClass test_obj;
std::thread t7(&TestClass::non_static_member_func, &test_obj, "非静态函数传参");
std::thread t9([](int a, int b) {
std::cout << "Lambda:" << a + b << std::endl;
}, 10, 20);
t2.join();
t5.join();
t6.join();
t7.join();
t9.join();
std::cout << "\n线程执行完毕" << std::endl;
std::thread t10(normal_func_with_args, 10, "拷贝测试");
std::thread t11(std::move(t10));
t11.join();
t_empty = std::thread(normal_func_with_args, 20, "移动赋值测试");
std::cout << "移动赋值后t_empty可join:" << t_empty.joinable() << std::endl;
t_empty.join();
return 0;
}
但是要注意
有些线程不能被join函数回收

4.thread::detach;
void detach();
将std::thread对象与它关联的执行线程分离,使得:
执行线程成为后台线程(守护线程),由操作系统接管其生命周期和资源释放。
原std::thread对象变为不可 joinable 状态(无法再调用join()或detach())。
分离后的子线程会在后台继续执行,直到任务完成,或主线程退出(此时子线程会被操作系统强制终止)。
仅可在joinable()状态调用:对joinable() == false的对象调用detach(),会抛出std::system_error异常。
分离后无法再关联:分离后的线程无法通过原std::thread对象控制(如join()),也无法重新关联。
主线程退出的风险:如果主线程先于分离的子线程退出,子线程会被强制终止(资源可能无法正常释放)。
避免局部变量的生命周期问题:子线程若访问主线程的局部变量,主线程退出后变量销毁,子线程会出现未定义行为。
5.swap
//成员函数版本
void swap(std::thread& other) noexcept; // noexcept:不会抛出异常
other std::thread&(非 const 左值引用) 与当前线程对象(*this)交换线程所有权的另一个线程对象。
非 const 左值引用:
参数必须是可修改的左值(不能是 const 对象、临时对象、右值),因为交换操作会修改other的内部状态(交换线程所有权)。如果传入const std::thread&,编译器会直接报错。
无状态限制:
other可以是任意状态的std::thread对象(既可以是joinable()的有效线程对象,也可以是默认构造的、已join()/detach()的非joinable对象)。
noexcept 保证:
函数标记为noexcept,意味着参数传递和交换过程中不会抛出异常,是线程安全的操作(由标准库实现保证)。
//非成员函数版本
void swap(std::thread& lhs, std::thread& rhs) noexcept;
lhs std::thread&(非 const 左值引用) 第一个需要交换的线程对象(左值)
rhs std::thread&(非 const 左值引用) 第二个需要交换的线程对象(左值)
两个参数都是非 const 左值引用,不能是 const 对象、临时对象或右值。
两个参数可以是任意状态的std::thread对象(joinable / 非 joinable)。
函数标记为noexcept,无异常风险。
6.this_thread命名空间内的函数

1.get_id()
std::thread::id get_id() noexcept;
作用:获取当前线程的唯一标识符(线程 ID)。
用途:可以通过线程 ID 区分不同线程(比如打印日志时标记线程、判断两个操作是否在同一线程执行)。
返回值:std::thread::id 类型(可直接打印或用于比较)。
2.yield()
void yield() noexcept;
作用:让当前线程主动让出 CPU 时间片,提示操作系统调度器 “可以先让其他线程运行”。
用途:适用于当前线程暂时没有紧急任务时,主动给其他线程分配运行机会(但调度器不一定会立即切换线程,只是一个 “建议”)。
3. sleep_until()
template <class Clock, class Duration>
void sleep_until(const std::chrono::time_point<Clock, Duration>& abs_time) noexcept;
作用:让当前线程休眠到指定的 “时间点”,到达该时间点后才会继续执行。
用途:需要精确控制线程在某个具体时间(比如 “2025-12-18 15:30:00”)恢复运行时使用。
依赖:需要配合 C++ 的时间点类型(如 std::chrono::system_clock::time_point)使用。
4. sleep_for()
template <class Rep, class Period>
void sleep_for(const std::chrono::duration<Rep, Period>& rel_time) noexcept;
作用:让当前线程休眠指定的 “时间段”(比如休眠 2 秒、500 毫秒),时间到后恢复执行。
用途:是最常用的 “让线程暂停一段时间” 的方式(比如模拟耗时操作、控制执行频率)。
依赖:配合 C++ 的时间段类型(如 std::chrono::seconds(2)、std::chrono::milliseconds(500))使用。
int main() {
std::cout << "休眠1秒\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "1秒后\n\n";
auto target = std::chrono::system_clock::now() + std::chrono::seconds(2);
std::cout << "休眠到2秒后\n";
std::this_thread::sleep_until(target);
std::cout << "2秒后\n";
return 0;
}
7.thread成员变量
1. id(Thread id)
定义:std::thread::id 是std::thread的公共成员类型,用于表示线程的唯一标识符。
作用:
作为std::this_thread::get_id()或std::thread::get_id()的返回类型,用来标识一个线程(进程内每个线程的id是唯一的)。
支持比较操作(==、!=等):可以判断两个id是否对应同一个线程。
支持输出操作(可直接用std::cout打印,便于调试)。
特点:跨平台通用(不依赖操作系统),是 C++ 标准定义的抽象线程标识。
2. native_handle_type(Native handle type)
定义:std::thread::native_handle_type 是std::thread的公共成员类型,代表操作系统原生的线程句柄类型(与平台强相关)。
例如:在 Linux 下对应pthread_t(POSIX 线程句柄);在 Windows 下对应HANDLE(Win32 线程句柄)。
作用:
作为std::thread::native_handle()成员函数的返回类型,用于获取线程的操作系统原生句柄。
可以通过原生句柄调用平台特定的线程 API(比如设置线程优先级、绑定 CPU 核心等,这些功能是std::thread标准接口未覆盖的)。
特点:平台相关(不同操作系统的native_handle_type类型不同),会破坏代码的可移植性,通常仅在需要调用系统原生线程功能时使用。
8.thread::get_id
std::thread::id get_id() const noexcept;
用法:通过std::thread对象调用,比如my_thread.get_id();
注意:主线程没有对应的std::thread对象,要拿主线程的 ID,得用std::this_thread::get_id()(这是一个全局函数)。
返回值:返回的是std::thread::id类型的对象(可以理解为 “线程 ID 的专用类型”),
thread::get_id()是某个线程对象的成员函数,获取 “该对象关联线程” 的 ID;
this_thread::get_id()是命名空间下的函数,获取 “当前执行线程” 的 ID。
9.thread:: hardware_concurrency [static]
static unsigned int hardware_concurrency() noexcept;
身份:std::thread的静态成员函数(不用创建线程对象,直接用std::thread::hardware_concurrency()就能调用)。
功能:查你电脑 CPU “能同时并行跑的任务数”(通常等于 CPU 的逻辑核心数,比如 4 核 8 线程的 CPU,这个函数返回的数大概率是 8)。
用途:写多线程程序时,参考这个数来决定开多少个线程更高效(比如按核心数开线程,避免开太多线程反而拖慢速度)。
10.thread::operator=

1. 可用的:移动赋值(move (1))
2. 禁用的:拷贝赋值(copy [deleted] (2))
1778

被折叠的 条评论
为什么被折叠?



