在《多線程編程之數據訪問互斥》一文中簡單介紹了原子鎖,這里再詳細說一下原子鎖的概念和用途。
(1)簡單數據操作
如果在一個多線程環境下對某個變量進行簡單數學運算或者邏輯運算,那么就應該使用原子鎖操作。因為,使用臨界區、互斥量等線程互斥方式將涉及到很多操作系統調用和函數調用等,效率肯定不如原子操作高。比如有這樣一個例子:
unsigned int count = 0; int data_process() { if(/* conditions */){ EnterCriticalSection(&cs); ++ count; LeaveCriticalSection(&cs); } }
這里只有簡單的數學操作,完全可以應用操作系統提供的原子操作來替代,效率會高不少:
unsigned int count = 0; int data_process() { if(/* conditions */){ InterLockedIncrement (&count); } }
(2)代碼段中的互斥
還是以臨界區為例,比如在代碼段中應用到了如下的臨界區:
void data_process() { EnterCriticalSection(&cs); do_something(); LeaveCriticalSection(&cs); }
這里其實也可以利用原子鎖來代替臨界區,實現方式如下:
unsigned int lock = 0; void data_process() { while(1 == InterLockedCompareExchange(&lock, 1, 0)); do_something(); lock = 0; }
InterLockedCompareExchange方法的含義是:將第一個參數的值與第三個參數的值進行比較,如果相等則與第二個參數的值進行交換,如果不相等則不進行操作;返回值為第一個參數的初始值,該函數所進行的操作為原子操作,不會被多線程中斷,可適用於所有CPU。
上面的代碼含義就是不斷監測lock的值,當lock值為0時,InterLockedCompareExchange就會將其變為1,並執行do_something(),最后將lock還原為0。當然,如果lock此時為1,這個while循環就會不斷地執行(“忙等”)。
其實說到這里,我們就會發現這里有一個問題:如果另外有一個線程將lock變為1並且需要執行很長的時間,那么這里豈不成了瘋等?沒錯,所以說這種原子鎖方法適用於短時間操作線程的互斥場合,並不能替代所有系統互斥鎖調用場合。臨界區在此時就會表現得更有優越性。