多线程基础
一、C++多线程基础
- 线程概念:线程是操作系统能够调度的最小执行单元,同一进程内的多个线程共享内存空间
- 头文件:
#include <thread>
- 线程生命周期:创建->执行->销毁(需显式管理)
- 注意事项:
- 线程函数参数建议使用值传递
- 注意数据竞争问题(需配合互斥锁使用)
- 主线程退出前必须处理所有子线程
二、核心函数详解
1. std::thread()
// 创建线程的三种方式
void func1();
void func2(int num);
// 方式1:普通函数
std::thread t1(func1);
// 方式2:带参数的函数
std::thread t2(func2, 42);
// 方式3:Lambda表达式
std::thread t3([](){
std::cout << "Lambda thread" << std::endl;
});
特性:
- 构造函数立即启动线程
- 参数自动转发给线程函数
- 必须处理线程对象(join或detach)
2. join()
std::thread t(func);
t.join(); // 阻塞当前线程,直到t执行完成
特点:
- 同步线程执行顺序
- 每个线程对象只能调用一次
- 调用后线程对象不再关联实际线程
3. joinable()
if(t.joinable()) {
t.join(); // 或t.detach()
}
判断条件:
- 线程已被创建(关联实际系统线程),正在进行的线程返回true
- 尚未被join或detach
4. detach()
std::thread t(func);
t.detach(); // 分离线程
特点:
- 线程在后台独立运行(守护线程)
- 失去对线程的直接控制
- 必须确保线程函数内的资源有效性
三、使用示例
#include <iostream>
#include <thread>
void print_num(int num) {
std::cout << "Number: " << num << std::endl;
}
int main() {
std::thread worker(print_num, 42);
if(worker.joinable()) {
worker.join(); // 或detach()
}
return 0;
}
线程函数中的数据未定义的错误
1.临时变量导致的传参错误
传递临时变量,临时变量在thread函数结束后销毁,没有传递到func里,导致未定义错误
#include<iostream>
#include<thread>
void func(int& x) {
x += 1;
}
int main() {
std::thread t(func, 1); //传递临时变量,临时变量在thread函数结束后销毁,没有传递到func里,导致未定义错误
t.join();
return 0;
}
解决方法:创建一个持久变量
#include<iostream>
#include<thread>
void func(int& x) {
x += 1;
std::cout << x << " ";
}
int main() {
int x = 1; //将变量复制到一个持久的对象
std::thread t(func, std::ref(x));//将变量的引用传递给线程
t.join();
return 0;
}
2.传递指针或引用指向局部变量的问题
test函数执行结束,a立刻释放,无法继续传进线程中的func函数中
#include <iostream>
#include<thread>
std::thread t;
void func(int& x) {
x += 1;
}
void test() {
int a = 1;
t = std::thread(func, std::ref(a));
}
int main()
{
test();
t.join();
return 0;
}
解决办法,把a 放到外面,a 变成一直可以被取到的全局变量
#include <iostream>
#include<thread>
std::thread t;
int a = 1;
void func(int& x) {
x += 1;
}
void test() {
t = std::thread(func, std::ref(a));
}
int main()
{
test();
t.join();
return 0;
}
3. 传递指针或引用指向已释放的内存的问题
指针在传进去之前delete,导致传进去的是空指针(不指向1)
#include<iostream>
#include<thread>
std::thread t;
void func(int* x) {
std::cout << *x << std::endl;
}
int main() {
int* ptr = new int(1);
std::thread t(func, ptr);
delete ptr;
t.join();
return 0;
}
解决办法
取消提前释放即可或使用智能指针
4. 类成员函数作为入口函数,类对象被提前释放
#include<iostream>
#include<thread>
#include<Windows.h>
class A {
public:
void func() {
Sleep(1000);
std::cout << "6" << std::endl;
}
};
int main() {
A *a;
std::thread t(&A::func, a);
delete a;
t.join();
}
解决办法:使用智能指针
#include<iostream>
#include<thread>
#include<Windows.h>
class A {
public:
void func() {
Sleep(1000);
std::cout << "6" << std::endl;
}
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();//使用智能指针地址一直有效,不会出现提前释放的问题
std::thread t(&A::func, a);
t.join();
}
5.入口函数为类的私有成员函数
#include<iostream>
#include<thread>
#include<Windows.h>
class A {
private:
void func() {
Sleep(1000);
std::cout << "6" << std::endl;
}
};
void thread_func() {
std::shared_ptr<A> a = std::make_shared<A>();
std::thread t(&A::func, a);
t.join();
}
int main() {
thread_func();
}
解决办法:使用友元函数
#include<iostream>
#include<thread>
#include<Windows.h>
class A {
private:
friend void thread_func();
void func() {
Sleep(1000);
std::cout << "6" << std::endl;
}
};
void thread_func() {
std::shared_ptr<A> a = std::make_shared<A>();
std::thread t(&A::func, a);
t.join();
}
int main() {
thread_func();
}
朝饮花上露,夜卧松下风。
云英化为水,光采与我同。 —王昌龄