今天在项目的过程中,程序运行一段时间,http服务就没办法响应了。通过日志排查,发现最后是因为在http响应的程序中,程序一直卡死再lock这个地方。通过半天思考自己的代码,貌似一直没想通自己这个地方为什么会死锁,貌似我程序没有出现啊?我都是在同一个对象同一个函数加锁和解锁成对出现的啊?不可能出现这个函数没解锁又上锁的问题啊?
上锁和解锁的相关代码如下:
1 bool WorkQueue::do_add_work(WorkBase* work) 2 { 3 // ELogPrint("add lock"); 4 if (0 != pthread_mutex_lock(&m_queue_lock)) { 5 ELogPrint("lock failed"); 6 // delete work; 7 // work = NULL; 8 return false; 9 } 10 11 while (m_queue_size >= MAX_WORK_NUMBER){ 12 DLogPrint("waiting producer cond:queue size:%d",m_queue_size); 13 pthread_cond_wait(&m_producer_cond, &m_queue_lock); // when thread wake up, the mutext is locked already 14 DLogPrint("receive producer cond,queue size:%d",m_queue_size); 15 } 16 17 m_work_queue.push_back(work); 18 m_queue_size++; 19 // //这里需要排重,防止重复 20 // //遍历 21 // bool find=false; 22 // list<WorkBase*>::iterator iter=m_work_queue.begin(); 23 // for(;iter!=m_work_queue.end();){ 24 // WorkBase*pW=*iter; 25 // if(pW==work){//如果相等 26 // find=true; 27 // } 28 // else{ 29 // iter++; 30 // } 31 // } 32 // if(!find){ 33 // m_work_queue.push_back(work); 34 // m_queue_size++; 35 // } 36 // DLogPrint("add broadcast or signal worker cond"); 37 /* wake up a worker thread */ 38 pthread_cond_signal(&m_worker_cond); 39 // pthread_cond_broadcast(&m_worker_cond); 40 41 pthread_mutex_unlock(&m_queue_lock); 42 // DLogPrint("add unlock"); 43 return true; 44 } 45 46 WorkBase* WorkQueue::get_work() 47 { 48 WorkBase* work = NULL; 49 if (0 != pthread_mutex_lock(&m_queue_lock)){ 50 ELogPrint("get lock failed"); 51 return work; 52 } 53 54 while (m_queue_size == 0){ 55 // DLogPrint("waiting worker cond:queue size:%d",m_queue_size); 56 pthread_cond_wait(&m_worker_cond, &m_queue_lock); // when thread wake up, the mutext is locked already 57 // DLogPrint("receive worker cond,queue size:%d",m_queue_size); 58 } 59 60 // work = m_work_queue.front(); 61 // m_work_queue.pop(); 62 //取第一个元素 63 work = m_work_queue.front(); 64 m_work_queue.pop_front(); 65 m_queue_size--; 66 67 // DLogPrint("get broadcast or signal producer cond"); 68 /* wake up a sleeping producer, maybe there is one */ 69 pthread_cond_signal(&m_producer_cond); 70 // pthread_cond_broadcast(&m_producer_cond); 71 72 pthread_mutex_unlock(&m_queue_lock); 73 // DLogPrint("get unlock"); 74 return work; 75 }
之前都不会出现死锁的情况?无法现在是加了红色的那段代码啊,为什么就这么容易出现死锁呢?
后面想了一下,我们会在线程池和状态机中不断的添加任务和做任务,同时在处理外部信号的时候,因为我们的程序在http响应的过程中会去根据消息中的id找到这个task对象,然后调用这个task的add_task函数,将这个task添加到线程池中,所以如果在http处理的过程中,出现了超时,http_client就会重发消息,这样的话,在http的处理底层线程中,用了一个新的线程去处理,同时获取到和前面一个没响应的消息,获取的task对象是同一个,这样如果前面一次的add_task挂在了lock函数的位置,这次再来lock的话,是不是就会出现死锁的问题呢?
原文出处:https://www.cnblogs.com/lihaiping/p/10457744.html