在我的上一篇文章《本地POSIX線程庫》http://www.linuxidc.com/Linux/2013-10/91409.htm 中,提到了Futex一詞,發現好多讀者誤以為這是我的筆誤,將Mutex錯寫為Futex了。其實Futex是Linux的一種全新的線程同步原語。本文將為您解讀高效的Futex。
Futex是fast userspace mutex的縮寫,意思是快速用戶空間互斥體。Linux內核把它們作為快速的用戶空間的鎖和信號量的預制構件提供給開發者。Futex非常基礎,借助其自身的優異性能,構建更高級別的鎖的抽象,如POSIX互斥體。大多數程序員並不需要直接使用Futex,它一般用來實現像NPTL這樣的系統庫。
Futex其實就是可以由不同進程所共享使用的一塊內存。在這些進程中,並不需要有相同的地址。一個光禿禿的Futex,與信號量的語義是相同的;它有一個可以被原子增減的計數器;進程可以等待這個計數器值變為正數。
Futex的操作完全是在用戶空間,不需要進行上下文切換。內核僅在發生競爭的時候作一個公斷。它的本質結構是一個對齊的整數,僅由原子的匯編指令操作。進程們可以通過mmap,在共享段中訪問它,或許是由於進程們共享了內存空間,通常就把這樣的應用程序稱為多線程程序。
任何Futex的操作都起始於用戶空間,但是在必要的時候還是需要使用某些系統調用與內核通訊的。
要“up”一個Futex,需執行正確的匯編指令使主CPU原子的遞增這個整數。然後,檢查它是否已從0變為1,這說明沒有等待進程,操作完成。這是無競爭情況,這很快而且應該很普遍。
在競爭情況下,原子增量從-1(或者是其他的負數)開始變化。如果是這樣的話,說明有等待進程。用戶空間應立即將計數器設置為1,並通知內核喚醒那些正使用FUTEX_WAKE操作的等待進程。
正等待一個Futex時,“down”它是一個相反的操作。原子遞減這個計數器,並檢查它是否變為0,使操作完成,Futex無競爭。在所有其他的情況下,進程會設置計數器為-1,並請求內核等待其他進程“up”Futex。這是通過FUTEX_WAIT操作完成的。
Futex是由Hubertus Franke(IBM Thomas J. Watson研究中心),Matthew Kirkwood,Ingo Molnar (Red Hat)和Rusty Russell (IBM Linux科技中心)設計並維護的。最初的Futex的支持是從Linux2.5.7開始的,但是以上述語義有些不同。當前的語義是從Linux2.5.40獲得的,在Linux2.5.70至2.6.7,已經可以獲得更多的附加功能了。