admin管理员组

文章数量:1599762

声明了一个类,内部通过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;
}

=================================
通过设置标志位来避免上述死锁的方式。当开始析构时设置标记位,回调函数发现了标志位,就直接退出。

本文标签: 死锁情况conditionvariable