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

《线程池:Linux平台编译线程池动态库发生的死锁问题》

关于如何编译动态库可以移步《Linux:动态库动态链接与静态库静态链接》-CSDN博客

我们写的线程池代码是闭源的,未来想提供给别人使用,只需要提供so库和头文件即可。

系统默认库文件路径为:

usr/lib usr/loacl/lib

系统默认头文件路径为:

usr/include usr/local/include

g++ -fPIC -shared threadpool.cpp -o libtbpool.so -std=c++17

sudo mv libtbpool.so /usr/local/lib
sudo mv threadpool.h /usr/local/include
 
g++ 线程池测试项目.cpp -ltdpool -lpthread

//修改/ect/ld.so.conf.d/
//将库文件路径放进/ect/ld.so.conf.d/
//ldconfig更新缓存路径即可

在windows下运行好好的程序,在Linux下怎么又会发生死锁呢?

gdb attatch 线程id

info threads:查看当前程序所有线程信息,包括线程ID、线程状态等。看到四个线程好像都在阻塞等待“in __lll_lock_wait”。

thread 5进入五号线程,bt查看线程5堆栈信息。

thread 3进入3号线程,bt查看线程3堆栈信息。

可以看到,在post()函数里notify_all()阻塞了。也就是在线程在Result得到返回结果之后,唤醒notify_all()用户接收线程执行完任务的返回值的时候阻塞了。

// 实现一个信号量类
class Semaphore
{
public:
	Semaphore(int limit = 0)
		:resLimit_(limit)
	{}

	// 获取一个信号量资源
	void wait()
	{
		// 等待信号量有资源,没有资源,会阻塞当前线程
		std::unique_lock<std::mutex> lock(mtx_);
		cond_.wait(lock, [&]()->bool {return resLimit_ > 0; });
		resLimit_--;
	}

	// 增加一个信号量资源
	void post()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		resLimit_++;
		cond_.notify_all();
	}

private:
	int resLimit_;// 初始信号量资源个数
	std::mutex mtx_;
	std::condition_variable cond_;
};

来分析一下原因。

Linux上,这些Result对象也是局部对象,是要析构的!

执行任务也是需要花费时间的,但是主线程提交完任务,它才不管任务有没有执行完呢。出了作用域Result对象就析构了。

Result对象会调用它自己的析构函数析构。

Result对象成员变量就要析构,问题出现在Semaphore上,来看一下Semaphore的析构函数,也是默认的,那么mutex和condition_variable也会默认析构。

既然问题出现在cond这个条件变量上,我们来看一下cond系统是怎么实现的。

可以看到在VS下,条件变量析构会释放相应的资源的。

所以Result对象接收完任务的返回值,然后调用Result的sem信号量的sem_.post()函数,但是Result对象出了作用域以后就析构了,Semaphore也就析构了,所以在调用sem_.post()的时候,cond已经析构了,cond_.notify_all()这里啥也没做,不会阻塞,任务正常结束。

那么,我们猜测Linux下g++的库,条件变量析构没有释放相应的资源。

可以看到,Linux下条件变量的析构函数没有做任何事情。

Result对象出了作用域以后,就析构了,Semaphore也要析构,mutex和condition_variable变量也要析构,但是g++库里condtition_variable没有做任何事情,使用了一个已经出了生命周期的对象。

改起来也很简单:

// 实现一个信号量类
class Semaphore
{
public:
	Semaphore(int limit = 0)
		:resLimit_(limit)
		,isExit_(false)
	{}
	~Semaphore()
	{
		isExit_ = true;
	}
	// 获取一个信号量资源
	void wait()
	{
		if(isExit_)
			true;
		// 等待信号量有资源,没有资源,会阻塞当前线程
		std::unique_lock<std::mutex> lock(mtx_);
		cond_.wait(lock, [&]()->bool {return resLimit_ > 0; });
		resLimit_--;
	}

	// 增加一个信号量资源
	void post()
	{
		if(isExit_)
			true;
		std::unique_lock<std::mutex> lock(mtx_);
		resLimit_++;
		cond_.notify_all();
	}

private:
	std::atomic_bool isExit_;
	int resLimit_;// 初始信号量资源个数
	std::mutex mtx_;
	std::condition_variable cond_;
};

再去测试就没什么问题了。这样就解决了线程池在Linux下死锁的问题。 

相关文章:

  • JAVA-序列化与反序列化
  • 【机器学习】模型拟合
  • 【合新通信】---RF over fiber
  • linux sh脚本关于返回字符串调试问题(adb shell)
  • MySQL 安全传输
  • GenICam标准
  • Java基于SSM的农业电商服务系统小程序【附源码、文档说明】
  • 《港口危货储存单位主要安全管理人员》考试资料及答案解析
  • 七天MySQL密集学习计划
  • Cursor解锁Claude Max,助力AI编程新突破!
  • Linux常用指令(1)
  • 记一次MyBatis分页莫名其妙的失效,首次执行合适,后续执行分页失效且异常
  • 三阴性乳腺癌化疗和PD-L1联合阻断的独特细胞机制(文献)
  • 3. 轴指令(omron 机器自动化控制器)——>MC_ImmediateStop
  • ffmpeg库硬解码使用流程
  • Java高频面试之集合-15
  • SVN简明教程——下载安装使用
  • 【数据分析】数据筛选(布尔索引:一个判断条件)
  • SAP-ABAP: 采购申请创建(PR)BAPI_PR_CREATE 技术指南-详解
  • (2025|ICLR|华南理工,任务对齐,缓解灾难性遗忘,底层模型冻结和训练早停)语言模型持续学习中的虚假遗忘
  • 王一博赛车故障退赛冲上热搜,工作室回应:下次再战
  • 钱学森数据服务中心在沪上线,十万个数字资源向公众开放
  • 集合多家“最美书店”,松江成立书店联盟“书香满云间”
  • 2024年上海发生科技融资997起,位于全国第一
  • 2024年度全国十大考古新发现公布,武王墩一号墓等入选
  • 接棒路颖,国泰海通证券副总裁谢乐斌履新海富通基金董事长