動機

現在 main thread 生出 兩條thread 然後 main thread 要等兩條thread完成

然而有一定機率,兩條子thread的其中一條會整個停住 只有一條可以完成

how to cancel the freezed thread?

第一個方法是 在某個子thread完成時就去cancel另一條

這個方法只要能detach就能實現,但是detach因為不明原因, 被detach的thread會自己消失,跑不到最後,進而無法成功完成

這裡有detach出事的可能原因

第二個方法是 讓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中是因為

  1. 不知道為什麼需要mutex
  2. 要加在哪

如果加在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?(包的目的有?)

  1. 在thread中的動作有沒有相依於另一個thread
  2. 共用同一資源

一般用mutex都是用在多thread共用同一資源,但這個case是為了確保happen-before

Ref

就是這篇救了我