項目中遇到一個bug,因為接入了幾家越獄平台:91、同步推、PP助手,在設備上安裝了三個應用,啟用其中任意一個,另外二個啟動后無法創建發送socket消息,從而導致游戲直接死在登錄那里,再次點擊登錄時線程才會被喚醒(無法發送的原因定位到,是因為在調用sem_post方法后無法將線程喚醒)。之后我嘗試將信號量改為條件變量,就再也沒有遇到那個問題了。具體改寫的幾個方法:
sem_open/sem_init => pthread_cond_init
sem_close/sem_destroy => pthread_cond_destroy
sem_wait => pthread_cond_wait
sem_post => pthread_cond_signal
信號量不僅可以用於進程也可用於線程,它比條件變量要復雜很多,條件變量僅限於線程內使用。
翻看cocos2d-x的源碼中,紋理緩存用到了信號量:
//CCTextureCache.cpp
// lazy init
if (s_pSem == NULL)
{
#if CC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
s_pSem = sem_open(CC_ASYNC_TEXTURE_CACHE_SEMAPHORE, O_CREAT, 0644, 0);
if( s_pSem == SEM_FAILED )
{
CCLOG( "CCTextureCache async thread semaphore init error: %s\n", strerror( errno ) );
s_pSem = NULL;
return;
}
#else
int semInitRet = sem_init(&s_sem, 0, 0);
if( semInitRet < 0 )
{
CCLOG( "CCTextureCache async thread semaphore init error: %s\n", strerror( errno ) );
return;
}
s_pSem = &s_sem;
#endif
光信號量的初始化就得根據不同平台來寫代碼,而用條件變量進行替代則只需要一行代碼,不需要針對不同的平台寫不同的代碼,代碼量小了。
避免使用信號量,除了維護的代碼較多以外,還有一個重要的原因是它容易用錯。陳碩在他的著作《Linux多線程服務端編程》P85頁中明確指出了,避免使用信號量(semaphore),它的功能與條件變量重合,但容易出錯。在《並發編程的 15 條建議(譯)》也提及如果Mutex就能解決問題,就不要使用信號量semaphore。
關於使用信號量容易出錯的例子,這里倒有一個:關於sem_open(3),所有信號量這種東東最好不要在線程內使用,進程間通信就要好好去研究它了…
