天天看點

pthread_cancel引起的死鎖

最近發現程式無法終止,查證發現問題出現在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/

繼續閱讀