当前位置: 首页 > news >正文

thread---基本使用和常见错误

多线程基础

一、C++多线程基础

  1. 线程概念:线程是操作系统能够调度的最小执行单元,同一进程内的多个线程共享内存空间
  2. 头文件#include <thread>
  3. 线程生命周期:创建->执行->销毁(需显式管理)
  4. 注意事项
    • 线程函数参数建议使用值传递
    • 注意数据竞争问题(需配合互斥锁使用)
    • 主线程退出前必须处理所有子线程

二、核心函数详解

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();
}

朝饮花上露,夜卧松下风。
云英化为水,光采与我同。 —王昌龄

相关文章:

  • Could not initialize class io.netty.util.internal.Platfor...
  • 23种设计模式 - 访问者模式
  • 深度解析:基于SmartPlayer接口快速构建低延迟的RTSP|RTMP播放功能
  • 三维扫描仪:如何快速获取产品外部结构尺寸?
  • 用Java创建一个验证码的工具类
  • 室内定位精度方案对比
  • win32汇编环境,对话框中使用菜单示例一
  • 《DAMA数据管理知识体系指南》第二章 数据处理伦理读书笔记总结
  • GAMES101-现代计算机图形学入门笔记
  • Hutool - DB:基于 ActiveRecord 思想的 JDBC 封装数据操作工具
  • XUnity.AutoTranslator-deepseek——调用腾讯的DeepSeek V3 API,实现Unity游戏中日文文本的自动翻译
  • Java 第八章 异常(1)
  • 详解TCP协议多种机制
  • java | MyBatis-plus映射和golang映射对比
  • 详解Nginx 配置
  • 将Neo4j用于Python学习的创新方法
  • 操作系统3.1
  • 自用题库---面试使用
  • 黑盒测试和白盒测试常用的测试方法有哪些?
  • 【科研绘图系列】R语言绘制小提琴图、散点图和韦恩图(violin scatter plot Venn)
  • wordpress doc附件前加图标/360优化大师app下载
  • 在网站后台管理系统里产品说明怎么添加图片/中国互联网协会
  • 站长推广工具/seo岗位是什么意思
  • 网站怎样做301跳转/杭州seo薪资水平
  • 龙华、宝安最新通告/郑州seo关键词排名优化
  • 东莞建网站公司品牌/企业网站页面设计