Open yanksx233 opened 2 years ago
很帅,确实应该判断关闭信号,他其他用到关闭信号的函数也有这个问题
Hello,我也碰到了这个问题,我的解决办法是这样的:
在block_queue.h
内
template <class T>
bool BlockQueue<T>::Pop(T& data) {
std::unique_lock<std::mutex> lock(mutex_);
consume_cond_.wait(lock, [this] { return !queue_.empty() || is_close_; }); // 当队列中无数据时“消费者”阻塞
if (is_close_) {
return false;
}
data = queue_.front();
// std::cout << data << "\n";
queue_.pop_front();
produce_cond_.notify_one(); // 通知“生产者”
return true;
}
在~Log()
内不执行Log::Flush()
,直接使用fflush
的缓冲区
if (file_) {
std::lock_guard<std::mutex> lock(mutex_);
// Flush();
fflush(file_);
fclose(file_);
}
简单测试后好像并没有问题:)
主线程调用最后一次LOG_BASE后循环程序运行完毕,开始调用~Log():
若此时子线程正在写fp,则会出现死锁。
分析如下: 在~Log()中,首先主线程判断deque是否为空然后deque->flush()唤醒deque_中的consumer,直到deque为空。 假设deque.size() == 1,子线程执行deque->pop(str)后deque.size()==0,然后执行fputs(str.cstr(), fp)。 主线程则析构Log执行deque->Close(), 并在writeThread->join()处等待。然后子线程fputs执行完毕,重新判断循环条件deque->pop(str),进入deque->pop后,由于deque.size()==0,于是停在 deque->pop 中的 condConsumer_.wait(locker)处。而此时主线程正在 join 等待子线程结束,从而出现死锁。
测试如下: 多次运行test,直到出现死锁
另起终端:
使用gdb查看函数调用栈:
可以看到 Thread 1 正在join等待子线程结束,而 Thread 2 锁在pop中的condition_variable::wait处。
原因可能是Log中访问deque_时没有任何保护措施(同步操作)。由于本人技术有限,初步解决方案是pop的while中先判断 isclose 然后再cond_wait,可以解决此问题。