多线程使用std::unique_lock抛出Resource deadlock avoided错误如何解决?
问题原因
核心问题出在sendCommand函数里互斥锁的错误使用逻辑:
- 你在构造
unique_lock时已经传入了std::try_to_lock参数,这个阶段unique_lock已经自动调用了一次_writeMtx.try_lock()尝试加锁 - 紧接着你又手动调用了一次
lock.try_lock(),而std::mutex属于非递归互斥锁,同一个线程对已经持有的非递归互斥锁重复执行加锁操作(包括try_lock)属于未定义行为,GNU libstdc++的实现会直接抛出std::system_error,错误描述就是Resource deadlock avoided - 额外逻辑漏洞:当前代码不管加锁是否成功,都会直接执行
_serial.writeString,完全没有起到互斥保护的作用,会引发串口写操作并发冲突。
修复方案
修改sendCommand中互斥锁的使用逻辑,二选一即可:
方案1:使用阻塞加锁逻辑(推荐)
串口写入耗时极短,阻塞加锁几乎不会影响业务性能,代码最简洁稳定:
int DASEmulator::sendCommand(const QString &command) { QString fullCommand = "**" + command + ';'; qDebug() << "Sending" << fullCommand ; char e{}; { unique_lock<mutex> lock{_writeMtx}; e = _serial.writeString(fullCommand.toLatin1()); } if (e!=1) cerr << "writeString error: " << e << endl; else qDebug() << "Sent: " << fullCommand ; return (int)e; }
方案2:保留非阻塞加锁逻辑
如果确实需要非阻塞的加锁判断,直接判断构造后的锁持有状态即可,不要额外调用try_lock,同时加锁失败要跳过写入操作避免并发问题:
int DASEmulator::sendCommand(const QString &command) { QString fullCommand = "**" + command + ';'; qDebug() << "Sending" << fullCommand ; char e{}; { unique_lock<mutex> lock{_writeMtx, std::try_to_lock}; if (!lock.owns_lock()) { cout << "Could not acquire lock" << endl; e = -1; // 自定义错误码标识加锁失败 } else { e = _serial.writeString(fullCommand.toLatin1()); } } if (e!=1) cerr << "writeString error: " << e << endl; else qDebug() << "Sent: " << fullCommand ; return (int)e; }
内容的提问来源于stack exchange,提问作者trozzel
相关产品推荐
相关产品推荐

