最近發現程式無法終止,查證發現問題出現在pthread_cancel上。加鎖代碼如下:
IAidTaskPtr CAidThreadPool::getTask() {
IAidTaskPtr pTask = NULL;
while (m_bRun)
{
pTask = NULL;
{
CAutoLock lock(m_BusinessLock);
if ( m_listTasks.empty() )
{
m_BusinessLock.wait();// pthread_cond_wait()實作
continue;
}
if (!m_listTasks.empty()) {
pTask = m_listTasks.front();
m_listTasks.pop_front();
break;
}
}
}
return pTask;
}
pthread_cancel 調用并不等待線程終止,它隻提出請求。線程在取消請求(pthread_cancel)發出後會繼續運作,直到到達某個取消點(Cancellation Point)。取消點是線程檢查是否被取消并按照請求進行動作的一個位置。
pthread_cancel manual 說以下幾個 POSIX 線程函數是取消點:
pthread_join(3)
pthread_cond_wait(3)
pthread_cond_timedwait(3)
pthread_testcancel(3)
sem_wait(3)
sigwait(3)
而當pthread_cancel時,程式正好處于pthread_cond_wait這個取消點上,但為什麼還是發生了死鎖呢?
在Linux的實作中在真正wait之前,有這樣一段代碼:
/* Before we block we enable cancellation. Therefore we have to install a cancellation handler. */
__pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer);
而__condvar_cleanup,做了什麼事情呢?
/* Get the mutex before returning unless asynchronous cancellation is in effect. */
__pthread_mutex_cond_lock (cbuffer->mutex);
}
加上了鎖,而這段代碼是在pthread_cancel發生時會執行到,這也就直接導緻了死鎖。
解決:不使用pthread_cancel終止線程
其他解決辦法:
void cleanup(void *arg)
{
pthread_mutex_unlock(&mutex);
}
void* thread0(void* arg)
{
pthread_cleanup_push(cleanup, NULL); // thread cleanup handler
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
pthread_exit(NULL);
}
參考文獻:
http://www.linuxalgorithm.com/1086654/