動機
現在 main thread 生出 兩條thread 然後 main thread 要等兩條thread完成
然而有一定機率,兩條子thread的其中一條會整個停住 只有一條可以完成
how to cancel the freezed thread?
第一個方法是 在某個子thread完成時就去cancel另一條
這個方法只要能detach就能實現,但是detach因為不明原因, 被detach的thread會自己消失,跑不到最後,進而無法成功完成
第二個方法是 讓main thread等,直到一個子thread完成,就通知mainthraed去cancel另一條
這裡用condition variable就能讓main thread等,所以有以下的code
void child()
{
doing_something_may_consume_many_time_or_finish_immediately();
clean_up();
pthread_cond_notifiy(&cond) // assume we have a cond var from main thread
pthread_mutex_unlock(&lock) // assume we have a mutex from main thread
}
void main()
{
pthread_mutex_lock(&lock);
pthread_create(child);
pthread_create(child);
pthread_cond_wait(&cond,&lock);
// cancel freezed thread, and clean up
}
最初用的時候,不知道為什麼需要mutex 反正不是會被通知嗎? 為什麼需要mutex?
main thread waits forever (Lost Wakeup)
之後悲劇就發生了,兩條子thread都沒了,但是main thread卻在cond的wait?!
考慮到下面的case 在main thread到wait之前,兩條子thread就完成了
好吧,所以要確保在notify的時候,要有人wait but how??
所以我們需要mutex,直到碰到wait之前子thread都不能notify
void child()
{
doing_something_may_consume_many_time_or_finish_immediately();
pthread_mutex_lock(&lock);
if (another_thread_is_not_complete()) {
clean_up();
pthread_cond_notifiy(&cond) // assume we have a cond var from main thread
}
pthread_mutex_unlock(&lock) // assume we have a mutex from main thread
}
void main()
{
pthread_mutex_lock(&lock);
pthread_create(child);
pthread_create(child);
pthread_cond_wait(&cond,&lock);
// cancel freezed thread, and clean up
}
Spurious Wakeup
condition variable其實有的時候會被notify,但是沒有任何thread做notify!?
pthread的說法是完全精確的notify無法在所有平台上,完美的有效率的實作出來 所以會有虛假甦醒(Spurious Wakeup)的問題,但是pthread也不會把這個當成bug
所以要確保離開wait時,是我們期待的狀態
void child()
{
doing_something_may_consume_many_time_or_finish_immediately();
pthread_mutex_lock(&lock);
if (another_thread_is_not_complete()) {
clean_up();
pthread_cond_notifiy(&cond) // assume we have a cond var from main thread
} else {
// if another is complete, this child need not to do anything
// another thread should have done all clean up
}
pthread_mutex_unlock(&lock) // assume we have a mutex from main thread
}
void main()
{
pthread_mutex_lock(&lock);
pthread_create(child);
pthread_create(child);
while (both_child_threads_are_not_complete())
pthread_cond_wait(&cond,&lock);
// cancel freezed thread, and clean up
}
reflection
最初沒加lock在子thread中是因為
- 不知道為什麼需要mutex
- 要加在哪
如果加在child的開頭會擋到另一條child跑
doing_something_may_consume_many_time_or_finish_immediately()
如果開兩個cond var放在child的開頭,就變成有兩個wait, 如果一條freeze,就不用動了
到後面才想到,加在clean_up之前
從有新的thread出生開始,整個程式的執行就變成thread的code混合完成出生之後的code
而有mutex包起來的話,就可以當成在同一個function中執行,不論是不是在同一個thread
所以在concurrent programming中,要怎麼決定要不要包mutex?(包的目的有?)
- 在thread中的動作有沒有相依於另一個thread
- 共用同一資源
一般用mutex都是用在多thread共用同一資源,但這個case是為了確保happen-before