當前位置: 華文問答 > 數碼

多執行緒編程的時候,使用無鎖結構會不會比有鎖結構更加快?

2016-12-14數碼

具體情況需具體分析。

一部份朋友覺得用鎖會影響效能,其實鎖指令本身很簡單,影響效能的是鎖爭用(Lock Contention),什麽叫鎖爭用,就是你我都想進入臨界區,但只能有一個執行緒能進去,這樣就影響了並行度。可以去看看glibc中pthread_mutex_lock的源碼實作,在沒有contention的時候,就是一條CAS指令,內核都沒有陷入;在contention發生的時候,就選擇陷入內核然後睡覺,等待某個執行緒unlock後喚醒(詳見Futex)。

「只有一個執行緒在臨界區」這件事對lockfree也是成立的,只不過所有執行緒都可以進臨界區,最後只有一個執行緒可以make progress,其它執行緒再做一遍。

所以contention在有鎖和無鎖編程中都是存在的,那為什麽無鎖有些時候會比有鎖更快?他們的不同體現在拿不到鎖的態度:有鎖的情況就是睡覺,無鎖的情況就不斷spin。睡覺這個動作會陷入內核,發生context switch,這個是有開銷的,但是這個開銷能有多大呢,當你的臨界區很小的時候,這個開銷的比重就非常大。這也是為什麽臨界區很小的時候,換成lockfree效能通常會提高很多的原因。

再來看lockfree的spin,一般都遵循一個固定的格式:先把一個不變的值X存到某個局部變量A裏,然後做一些計算,計算/生成一個新的物件,然後做一個CAS操作,判斷A和X還是不是相等的,如果是,那麽這次CAS就算成功了,否則再來一遍。如果上面這個loop裏面「計算/生成一個新的物件」非常耗時並且contention很嚴重,那麽lockfree效能有時會比mutex差。另外lockfree不斷地spin引起的CPU同步cacheline的開銷也比mutex版本的大。

lockfree的意義不在於絕對的高效能,它比mutex的優點是使用lockfree可以避免死結/活鎖,優先級翻轉等問題。但是因為ABA problem、memory order等問題,使得lockfree比mutex難實作得多。

除非效能瓶頸已經確定,否則還是乖乖用mutex+condvar,等到以後出bug了就知道mutex的好了。如果一定要換lockfree,請一定要先profile,profile,profile!請確保時間花在刀刃上。