測試線程同步中出現的阻塞問題?

測試代碼如下:

#include &
#include &


#include &
#include &

struct msg {
char *key;
int signum;
};

void *count(void *word);

struct msg * maincount = NULL;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int main() {
pthread_t t1, t2;
struct msg *buf;
int num = 2;
pthread_mutex_lock(mutex);

struct msg msga[2];
msga[0].key = "hello
";
msga[0].signum = 1;
msga[1].key = "world
";
msga[1].signum = 2;
pthread_create(t1, NULL, count, (void *)msga[0]);
pthread_create(t2, NULL, count, (void *)msga[1]);
while(num--) {
printf("wait lock...
");
pthread_cond_wait(cond, mutex);
printf("have a lock...
");
buf = maincount;
printf("%s", buf-&>key);
printf("%d
", buf-&>signum);
if (maincount-&>signum == 1) {
pthread_join(t1, NULL);
printf("pthread 1 exit
");
}
else if(maincount-&>signum == 2){
pthread_join(t2, NULL);
printf("pthread 2 exit
");
}
}
return 0;
}

void *count(void *word) {
struct msg *mymain = (struct msg *)word;
pthread_mutex_lock(mutex);
maincount = mymain;
pthread_cond_signal(cond);
pthread_mutex_unlock(mutex);

return NULL;
}

兩次運行結果如下:

在第二次執行時出現永久阻塞,為什麼count函數中的pthread_cond_signal沒有喚醒循環中等候的線程?有沒有什麼好的解決方案?


這個錯誤很典型,原因是 pthread condvar 是 edge trigger,不是 level trigger。你 signal 的時候,如果沒有別的線程 wait,那麼這個事件就丟失了。

用條件變數實現事件等待器的正確與錯誤做法 - CSDN博客


一種可能形成死鎖的執行順序:

主線程 獲得鎖,主線程釋放鎖同時進入wait

t1線程獲得鎖,signum=1,t1線程signal,t1線程釋放鎖,t1線程退出

t2線程獲得鎖,signum=2,t2線程signal,t2線程釋放鎖,t2線程退出

主線程結束wait,主線程重新獲得鎖, signum==2分支,num--,繼續循環

主線程再次釋放鎖並進入wait,永久等待(錯過了t1線程的signal)。

你在程序中輸出更多的log就可以看到這個執行過程。


這個程序連同主線程是3個線程:

在主線程通過pthread_cond_wait釋放鎖並等待條件後,

第二個線程可能獲得鎖、運行完成、釋放鎖。

這時候有可能不是主線程獲得鎖,第三個線程也可能獲得鎖,並執行完,釋放鎖。

然後主線程才獲得鎖,並執行循環的後半部分,並在下一輪循環時等死。

這個程序存在並發問題。


推薦閱讀:

多線程執行順序控制?
求詳解該InterlockedIncrement的實現?
word2vec多線程優化時不加鎖的做法合理么?
ASIO + HTTP 如何打造高性能伺服器?
為什麼`atomic::fetch_add()`可以 relaxed memory order?

TAG:CC | Linux開發 | 多線程 |