线程池项目代码细节5(解决linux死锁问题)
您总结得非常准确!这是Linux下使用自定义动态库的完整流程。让我为您详细整理并补充一些细节。
📁 完整的部署和使用流程
1. 准备文件和目录结构
text
~/mylib/ ├── include/ │ └── mylib.h # 头文件 ├── lib/ │ └── libmylib.so # 动态库文件 └── test/└── main.cpp # 测试程序
2. 编译动态库(确保链接pthread)
bash
# 编译为位置无关代码 g++ -fPIC -c mylib.cpp -o mylib.o -I./include -std=c++17 -lpthread# 创建动态库(关键:链接pthread) g++ -shared -o lib/libmylib.so mylib.o -lpthread# 或者一步完成 g++ -fPIC -shared -o lib/libmylib.so mylib.cpp -I./include -std=c++17 -lpthread
3. 设置环境变量(临时测试)
bash
# 设置头文件搜索路径 export CPLUS_INCLUDE_PATH=~/mylib/include:$CPLUS_INCLUDE_PATH# 设置库文件搜索路径 export LIBRARY_PATH=~/mylib/lib:$LIBRARY_PATH export LD_LIBRARY_PATH=~/mylib/lib:$LD_LIBRARY_PATH
4. 编译测试程序(链接动态库)
bash
# 编译并链接动态库 g++ test/main.cpp -o test/main -lmylib -std=c++17 -lpthread# 显式指定路径(如果环境变量没设置) g++ test/main.cpp -o test/main -I~/mylib/include -L~/mylib/lib -lmylib -std=c++17 -lpthread
5. 永久配置系统库路径
bash
# 创建配置文件 sudo vim /etc/ld.so.conf.d/mylib.conf# 内容:添加您的库路径 /home/yourusername/mylib/lib# 更新动态链接器缓存 sudo ldconfig# 验证配置 ldconfig -p | grep mylib
🎯 详细步骤说明
步骤1:编译时的链接(-lpthread)
为什么需要?
std::thread
在底层使用 pthread 库动态库使用了线程,所以需要链接 pthread
编译库时和编译程序时都需要链接
bash
# 编译动态库时必须链接 g++ -fPIC -shared -o libmylib.so mylib.cpp -lpthread# 使用库的程序也必须链接 g++ main.cpp -o main -lmylib -lpthread
步骤2:运行时库路径配置
三种配置方法:
方法1:临时环境变量(测试用)
bash
export LD_LIBRARY_PATH=/path/to/your/lib:$LD_LIBRARY_PATH ./your_program
方法2:永久系统配置(生产环境)
bash
# 创建配置文件 sudo echo "/path/to/your/lib" > /etc/ld.so.conf.d/mylib.conf# 更新缓存 sudo ldconfig
方法3:编译时指定rpath(嵌入路径)
bash
g++ main.cpp -o main -lmylib -Wl,-rpath=/path/to/your/lib -L/path/to/your/lib
步骤3:头文件路径配置
两种配置方法:
方法1:环境变量
bash
export CPLUS_INCLUDE_PATH=/path/to/your/include:$CPLUS_INCLUDE_PATH
方法2:编译参数
bash
g++ main.cpp -o main -I/path/to/your/include -L/path/to/your/lib -lmylib -lpthread
在linux时运行无法退出,出现死锁问题。
用gdb拉起一个正在死锁的线程,使用info threads发现都在wait,死锁了,thread 5 进入相应线程,通过(gdb) bt可以查看每个线程的调用堆栈,发现主线程是正常的,子线程出了问题,发现是
condition_variable cond_
cond_.notify_all(); // 等待状态,释放mutex锁 通知条件变量wait的地方,可以起来干活了自己创建的信号量在post之后notify死锁了,在vs下条件变量析构会释放相应资源,就是自定义信号量的类里面的条件变量自己析构了,通过查看linux的条件变量condition_variable cond_;发现在析构时并没有释放资源。
void post(){std::unique_lock<std::mutex> lock(mtx_);resLimit_++;// linux下condition_variable的析构函数什么也没做// 导致这里状态已经失效,无故阻塞cond_.notify_all(); // 等待状态,释放mutex锁 通知条件变量wait的地方,可以起来干活了}
就是随着Result析构那里面的成员变量Semaphore也跟着析构了,所以条件变量condition_variable cond_也跟着析构了,因为linux析构什么的也没做,所以发生死锁。主要就是因为主线程没有等子线程,子线程还在调用post函数,使用了已经析构的资源cond_,
// 实现一个信号量类
class Semaphore
{
public:Semaphore(int limit = 0) :resLimit_(limit),isExit_(false){}~Semaphore() {isExit_ = true;}// 获取一个信号量资源void wait(){if (isExit_) {return;}std::unique_lock<std::mutex> lock(mtx_);// 等待信号量有资源,没有资源的话,会阻塞当前线程cond_.wait(lock, [&]()->bool {return resLimit_ > 0; });resLimit_--;}// 增加一个信号量资源void post(){if (isExit_) {return;}std::unique_lock<std::mutex> lock(mtx_);resLimit_++;// linux下condition_variable的析构函数什么也没做// 导致这里状态已经失效,无故阻塞cond_.notify_all(); // 等待状态,释放mutex锁 通知条件变量wait的地方,可以起来干活了}
private://最新添加std::atomic_bool isExit_;int resLimit_;std::mutex mtx_;std::condition_variable cond_;
};
添加代码,如果Semaphore析构就不执行post代码。
死锁ps -u查看进程
gdb attach 6359
info threads
(gdb) bt
thread 5
bt