声明了一个类,内部通过std::unique_ptr使用了muduo::net::TcpClient
class SendData
{
public:
SendData();
~SendData() = default;
private:
void onConnection(const muduo::net::TcpConnectionPtr& conn)
{
// do something
m_cv.notify_one()
}
private:
std::unique_ptr<muduo::net::TcpClient> m_pTcpClient;
std::condition_variable m_cv
};
在程序内部创建了TcpClient,并连接了服务端。
连接断开的方法,采用了释放TcpClient对象的方式。
当TcpClient对象释放时会进行连接断开,此时会将连接结果通过回调函数反馈回来。
EventLoop反馈断开结果时,可能对象已经释放或者说condition_variable对象已经释放了。
回调函数还用的原来的地址执行了回调函数,此时执行到m_cv.notify_one可能会导致卡住
(linux_3.10 中通过gdb找到卡住的线程,通过调用堆栈是condition_variable中的__lll_lock_wait锁住)。
#0 0x00007ffff78c554d in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007ffff78c314d in pthread_cond_signal@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#2 0x00007ffff7b84b09 in std::condition_variable::notify_one() () from /lib64/libstdc++.so.6
=================================
通过写测试程序进行模拟,也没有模拟出来。如果有好的模拟方法,请指导。
#include <stdlib.h>
#include <stdio.h>
#include <condition_variable>
#include <thread>
int main()
{
std::condition_variable *pcv;
{
std::condition_variable cv;
pcv = &cv;
for(int i = 0; i < 10; i++)
{
cv.notify_one();
fprintf(stderr, "notify %d times.\n", i + 1);
}
cv.notify_all();
}
std::this_thread::sleep_for(std::chrono::seconds(1));
pcv->notify_one();
fprintf(stderr, "use dtor cv to notify_one.\n");
return 0;
}
=================================
通过设置标志位来避免上述死锁的方式。当开始析构时设置标记位,回调函数发现了标志位,就直接退出。