版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、自旋鎖分類: 瘋狂內(nèi)核之同步與互斥2010-05-18 19:59 395人閱讀 評論(0) 收藏 舉報加鎖(locking)是一種廣泛應(yīng)用的同步技術(shù)。當(dāng)內(nèi)核控制路徑必須訪問共享數(shù)據(jù)結(jié)構(gòu)或進(jìn)入臨界區(qū)時,就需要為自己獲取一把“鎖”。由鎖機(jī)制保護(hù)的資源非常類似于限制于房間內(nèi)的資源,當(dāng)某人進(jìn)入房間時,就把門鎖上。如果內(nèi)核控制路徑希望訪問資源,就試圖獲取鑰匙“打開門”。當(dāng)且僅當(dāng)資源空閑時,它才能成功。然后,只要它還想使用這個資源,門就依然鎖著。當(dāng)內(nèi)核控制路徑釋放了鎖時,門就打開,另一個內(nèi)核控制路徑就可以進(jìn)入房間。下圖顯示了鎖的使用。5個內(nèi)核控制路徑(P
2、0,PI,P2,P3和P4)試圖訪問兩個臨界區(qū)(C1和C2)。內(nèi)核控制路徑P0正在C1中,而P2和P4正等待進(jìn)人C1。同時,P1正在C2中,而P3正在等待進(jìn)入C2。注意P0和P1可以并行運行。臨界區(qū)C3的鎖現(xiàn)在打開著,因為沒有內(nèi)核控制路徑需要進(jìn)人C3。 Linux鎖的應(yīng)用之一在多處理器環(huán)境中,取名叫自旋鎖(spin lock)。如果內(nèi)核控制路徑發(fā)現(xiàn)自旋鎖“開著”,就獲取鎖并繼續(xù)自己的執(zhí)行。相反,如果內(nèi)核控制路徑發(fā)現(xiàn)鎖由運行在另一個CPU上的內(nèi)核控制路徑“鎖著”,就在周圍“旋轉(zhuǎn)”,反復(fù)執(zhí)行一條緊湊的循環(huán)指令,直到鎖被釋放。自旋鎖的循環(huán)指令表示“忙等”。即使等待的內(nèi)核控制路徑
3、無事可做(除了浪費時間),它也在CPU上保持運行。不過,自旋鎖通常非常方便,因為很多內(nèi)核資源只鎖1毫秒的時間片段;所以說,等待自旋鎖的釋放不會消耗太多CPU的時間。一般來說,由自旋鎖所保護(hù)的每個臨界區(qū)都是禁止內(nèi)核搶占的。在單處理器系統(tǒng)上,這種鎖本身并不起鎖的作用,自旋鎖技術(shù)僅僅是用來禁止或啟用內(nèi)核搶占。請注意,在自旋鎖忙等期間,因為并沒有進(jìn)入臨界區(qū),所以內(nèi)核搶占還是有效的,因此,等待自旋鎖釋放的進(jìn)程有可能被更高優(yōu)先級的所取代。這種設(shè)計是合理的,因為不能因為占用CPU太久而使系統(tǒng)死鎖。 在Linux中,每個自旋鎖都用spinlock_t結(jié)構(gòu)表示:typedef struct
4、; raw_spinlock_t raw_lock;#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) unsigned int break_lock;#endif#ifdef CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; void *owner;#endif#ifdef CONFIG_DEBUG_LOCK_ALLOC
5、; struct lockdep_map dep_map;#endif spinlock_t;typedef struct volatile unsigned int slock; raw_spinlock_t;其中包含兩個重要的字段意義如下:slock:該字段表示自旋鎖的狀態(tài):值為1表示“未加鎖”狀態(tài),而任何負(fù)數(shù)和0都表示“加鎖”狀態(tài)。break_lock:表示進(jìn)程正在忙等自旋鎖(只在內(nèi)核支持SMP和內(nèi)核搶占的情況下使用該標(biāo)志)。內(nèi)核提供六個宏用于初始化、測試及設(shè)置自旋鎖。所有這些宏都是基于原子操作的,這樣可以保證即使有多個運行在不同CPU上
6、的進(jìn)程試圖同時修改自旋鎖,自旋鎖也能夠被正確地更新。 1、spin_lock_init 初始化自旋鎖,并把自旋鎖的lock->raw_lock置為1(未鎖)# define spin_lock_init(lock) /do
7、0; / static struct lock_class_key _key; /
8、160; / _spin_lock_init(lock), #lock, &_key); / while (0)void _spin_lock_init(spinlock_t *lock, const char *name, struct lock_class_key *key)#ifdef C
9、ONFIG_DEBUG_LOCK_ALLOC /* * Make sure we are not reinitializing a held lock: */ debug_check_no_locks_freed(void *)lock, sizeof(*lock); lockdep_init_map(&lock->dep_map, name, key, 0);#endif
10、60; lock->raw_lock = (raw_spinlock_t)_RAW_SPIN_LOCK_UNLOCKED; lock->magic = SPINLOCK_MAGIC; lock->owner = SPINLOCK_OWNER_INIT; lock->owner_cpu = -1;#define _RAW_SPIN_LOCK_UNLOCKED 1 #define SP
11、INLOCK_MAGIC 0xdead4ead#define SPINLOCK_OWNER_INIT (void *)-1L)2、spin_unlock 把自旋鎖置為1(未鎖)#if defined(CONFIG_DEBUG_SPINLOCK) | defined(CONFIG_PREEMPT) | / !defined(CONFIG_SMP)# define spin_unlock(lock)
12、60; _spin_unlock(lock)#else /我們還是重點關(guān)注后面的吧# define spin_unlock(lock) _raw_spin_unlock(&(lock)->raw_lock)#endif void _lockfunc _spin_unlock(spinlock_t *lock) spin_release(&lock->dep_map, 1, _RET_IP_); _ra
13、w_spin_unlock(lock); preempt_enable();# define _raw_spin_unlock(lock) _raw_spin_unlock(&(lock)->raw_lock)static inline void _raw_spin_unlock(raw_spinlock_t *lock) _asm_ _volatile_( _r
14、aw_spin_unlock_string );#define _raw_spin_unlock_string / "movb $1,%0" / :"+m" (lock->slock) : : "memory"spin_unlock宏釋放以前獲得的自旋鎖,上面的代碼本質(zhì)上執(zhí)行下列匯編語言指令:movb $1, slp->slock并在隨后調(diào)用preempt_enable()(如果
15、不支持內(nèi)核搶占,preempt_enable()什么都做)。注意,因為現(xiàn)在的80x86微處理器總是原子地執(zhí)行內(nèi)存中的只寫訪問,所以不用lock字節(jié)。3、spin_unlock_wait 等待,直到自旋鎖變?yōu)?(未鎖)#define spin_unlock_wait(lock) _raw_spin_unlock_wait(&(lock)->raw_lock)#define _raw_spin_unlock_wait(lock) / do while (_raw_spin_is_locked(lock) cpu_
16、relax(); while (0)#define _raw_spin_is_locked(x) / (*(volatile signed char *)(&(x)->slock) <= 0) /如果大于0則為真,表示未鎖,則跳出while循環(huán)#define cpu_relax() rep_nop() /在循環(huán)中執(zhí)行一條空指令:static inline void rep_nop(void) _asm_ _volatile_(&q
17、uot;rep;nop": : :"memory");4、spin_is_locked( ) 如果自旋鎖被置為1(未鎖),返回0;否則,返回1#define spin_is_locked(lock) _raw_spin_is_locked(&(lock)->raw_lock)#define _raw_spin_is_locked(x) / (*(volatile signed char *)(&(x)->slock) <=
18、 0)5、spin_trylock( ) 把自旋鎖置為0(鎖上),如果原來鎖的值是1,則返回1;否則,返回0#define spin_trylock(lock) _cond_lock(_spin_trylock(lock)int _lockfunc _spin_trylock(spinlock_t *lock) preempt_disable(); if (_raw_spin_trylock(lock)
19、0; spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); return 1; preempt_enable(); return 0; 6、spin_lock 加鎖:循環(huán),直到自旋鎖變?yōu)?(未鎖),然后,把自旋鎖置為0(鎖上) spin_lock是最重要的一個宏。首先,我
20、們看到在include/spinlock.h頭文件里,有:#if defined(CONFIG_SMP) | defined(CONFIG_DEBUG_SPINLOCK)# include <linux/spinlock_api_smp.h> /多處理器情況#else# include <linux/spinlock_api_up.h> /單處理器情況#endif#define spin_lock(lock) _spin_l
21、ock(lock)#ifdef _LINUX_SPINLOCK_API_UP_H #define _spin_lock(lock) _LOCK(lock) /單處理器情況 #else 注意,該代碼上邊有一句#if !defined(CONFIG_PREEMPT) | !defined(CONFIG_SMP) | / defined(CONFIG_DE
22、BUG_LOCK_ALLOC)別去管它,因為上邊的英文注釋寫得很清楚了,這句代碼的意思是即使沒有定義內(nèi)核搶占或SMP,或者是自旋鎖調(diào)試,只要lockdep激活了,也就是我們在剛才spinlock_t定義的那里看到的#ifdef CONFIG_DEBUG_LOCK_ALLOC,都會假設(shè)在整個鎖的調(diào)試期間保持關(guān)中斷。這句#if就是這個意思,千萬別理解成沒有定義內(nèi)核搶占、SMP或自旋鎖調(diào)試了,切記切記。/* * If lockdep is enabled then we use the non-preemption spin-ops * even on CONFIG_PREEMP
23、T, because lockdep assumes that interrupts are * not re-enabled during lock-acquire (which the preempt-spin-ops do): */多處理器情況,并且允許內(nèi)核搶占: void _lockfunc _spin_lock(spinlock_t *lock) /禁止搶占 preempt_disable(); /這個函數(shù)在沒有定義自旋鎖調(diào)試的時候是空函數(shù),我們不
24、去管它 spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); /相當(dāng)于_raw_spin_lock(lock) LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); 在沒有定義自旋鎖調(diào)試的時候,LOCK_CONTENDED宏定義如下#define LOCK_CONTENDED(_lock, try, lock) /
25、60; lock(_lock)我們看到其實就是調(diào)用_raw_spin_lock宏(位于include/linux/spinlock.h):# define _raw_spin_lock(lock) _raw_spin_lock(&(lock)->raw_lock)于是,定位到include/asm-i386/Spinlock.hstatic inline void _raw_spin_lock(raw_spinlock_t *lock) asm(_
26、raw_spin_lock_string : "+m" (lock->slock) : : "memory");展開:#define _raw_spin_lock_string / "/n1:/t" / /原子減,如果不為負(fù),跳轉(zhuǎn)到3f,3f后面沒有任何指令,即為退出 LOCK_PREFIX " ; decb %0/n/t" /
27、160; "jns 3f/n" / "2:/t" / /重復(fù)執(zhí)行nop,nop是x86的小延遲函數(shù),執(zhí)行空操作 "rep;nop/n/t" / /比較0與lock->slock的值,如果lock->slock不大于0,跳轉(zhuǎn)到標(biāo)號2,即繼續(xù)重復(fù)執(zhí)行nop "cmpb $0,%0/n/t" /
28、"jle 2b/n/t" / /如果lock->slock大于0,跳轉(zhuǎn)到標(biāo)號1,重新判斷鎖的slock成員 "jmp 1b/n" / "3:/n/t"在上面的函數(shù)中,大家可能對"jmp 1b/n“比較難以理解。在我們一般的觀念里,獲得一個鎖,將其值減1;釋放鎖時將其值加1;實際上在自旋鎖的實現(xiàn)中l(wèi)ock->slock只有兩個可能值,一個是0. 一個是1。釋放鎖的時候并不是將lock->slock加1,
29、而是將其賦為1。請看在前面的自旋鎖釋放代碼spin_unlock中的詳細(xì)分析。 讀寫自旋鎖分類: 瘋狂內(nèi)核之同步與互斥2010-05-18 20:24 337人閱讀 評論(0) 收藏 舉報讀/寫自旋鎖同樣是在保護(hù)SMP體系下的共享數(shù)據(jù)結(jié)構(gòu)而引入的,它的引入是為了增加內(nèi)核的并發(fā)能力。只要內(nèi)核控制路徑?jīng)]有對數(shù)據(jù)結(jié)構(gòu)進(jìn)行修改,讀/寫自旋鎖就允許多個內(nèi)核控制路徑同時讀同一數(shù)據(jù)結(jié)構(gòu)。如果一個內(nèi)核控制路徑想對這個結(jié)構(gòu)進(jìn)行寫操作,那么它必須首先獲取讀/寫鎖的寫鎖,寫鎖授權(quán)獨占訪問這個資源。這樣設(shè)計的目的,即允許對數(shù)據(jù)結(jié)構(gòu)并發(fā)讀可以提高系統(tǒng)性能。下圖
30、顯示有兩個受讀/寫鎖保護(hù)的臨界區(qū)(CI和C2)。內(nèi)核控制路徑R0和R1正在同時讀取C1中的數(shù)據(jù)結(jié)構(gòu),而W0正等待獲取寫鎖。內(nèi)核控制路徑W1正對C2中的數(shù)據(jù)結(jié)構(gòu)進(jìn)行寫操作,而R2和W2分別等待獲取讀鎖和寫鎖。 每個讀/寫自旋鎖都是一個rwlock_t結(jié)構(gòu):typedef struct raw_rwlock_t raw_lock;#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) unsigned int break_lock;#endif#ifde
31、f CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; void *owner;#endif#ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map;#endif rwlock_t;typedef struct volatile unsigned int lock; raw_rwlock_t;其lock字段是一個32位的字段,分為兩個不同的
32、部分:(1)24位計數(shù)器,表示對受保護(hù)的數(shù)據(jù)結(jié)構(gòu)并發(fā)地進(jìn)行讀操作的內(nèi)核控制路徑的數(shù)目。這個計數(shù)器的二進(jìn)制補碼存放在這個字段的023位。(2)“未鎖”標(biāo)志字段,當(dāng)沒有內(nèi)核控制路徑在讀或?qū)憰r設(shè)置該位,否則清0。這個“未鎖”標(biāo)志存放在lock字段的第24位。注意,如果自旋鎖為空(設(shè)置了“未鎖”標(biāo)志且無讀者),那么lock字段的值為0x01000000;如果寫者已經(jīng)獲得自旋鎖(“未鎖”標(biāo)志清0且無讀者),那么lock字段的值為0x00000000;如果一個、兩個或多個進(jìn)程因為讀獲取了自旋鎖,那么,lock字段的值為Ox00ffffff,Ox00fffffe等(“未鎖”標(biāo)志清0表示寫鎖定,不允許寫該數(shù)據(jù)
33、結(jié)構(gòu)的進(jìn)程,讀者個數(shù)的二進(jìn)制補碼在023位上;如果全為0,則表示有一個寫進(jìn)程在操作此數(shù)據(jù)結(jié)構(gòu))。與spinlock_t結(jié)構(gòu)一樣,rwlock_t結(jié)構(gòu)也包括break_lock字段。rwlock_init宏把讀/寫自旋鎖的lock字段初始化為0x01000000(“未鎖”),把break_lock初始化為0,算法類似spin_lock_init。進(jìn)程獲得讀寫自旋鎖的方式不僅有是否設(shè)置了內(nèi)核搶占選項而不同外,還跟讀或?qū)懙牟僮飨嚓P(guān)。前者的算法跟自旋鎖機(jī)制幾乎一樣,下面我們就重點討論后者: 1 為讀獲取和釋放一個鎖read_lock宏,作用于讀/寫自旋鎖的地址*lock,與上一篇博文所描述的
34、spin_lock宏非常相似。如果編譯內(nèi)核時選擇了內(nèi)核搶占選項,read_lock宏執(zhí)行與spin_lock()非常相似的操作,只有一點不同:該宏執(zhí)行_raw_read_trylock( )函數(shù)以在第2步有效地獲取讀/寫自旋鎖。void _lockfunc _read_lock(rwlock_t *lock) preempt_disable(); rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); LOCK_CONTEN
35、DED(lock, _raw_read_trylock, _raw_read_lock);在沒有定義調(diào)試自旋鎖操作時rwlock_acquire_read為空函數(shù),我們不去管它。所以_read_lock的實務(wù)函數(shù)是_raw_read_trylock:# define _raw_read_trylock(rwlock) _raw_read_trylock(&(rwlock)->raw_lock)static inline int _raw_read_trylock(raw_rwlock_t *lock) ato
36、mic_t *count = (atomic_t *)lock; atomic_dec(count); if (atomic_read(count) >= 0) return 1; atomic_inc(count); return 0;讀/寫鎖計數(shù)器lock字段是通過原子操作來訪問的。注意,盡管如此,但整個函數(shù)對計數(shù)器的操作并不是原子性的,利用原子操作主要目的是禁止內(nèi)核搶
37、占。例如,在用if語句完成對計數(shù)器值的測試之后并返回1之前,計數(shù)器的值可能發(fā)生變化。不過,函數(shù)能夠正常工作:實際上,只有在遞減之前計數(shù)器的值不為0或負(fù)數(shù)的情況下,函數(shù)才返回1,因為計數(shù)器等于0x01000000表示沒有任何進(jìn)程占用鎖,等于Ox00ffffff表示有一個讀者,等于0x00000000表示有一個寫者(因為只可能有一個寫者)。如果編譯內(nèi)核時沒有選擇內(nèi)核搶占選項,read_lock宏產(chǎn)生下面的匯編語言代碼: movl $rwlp->lock,%eax
38、 lock; subl $1,(%eax) jns 1f call _ _read_lock_failed 1:這里,_read_lock_failed()是下列匯編語言函數(shù): _ _read_lock_failed: lock; incl
39、 (%eax) 1: pause cmpl $1,(%eax) js 1b lock; decl (%eax) js _ _read_lock_failed
40、 retread_lock宏原子地把自旋鎖的值減1,由此增加讀者的個數(shù)。如果遞減操作產(chǎn)生一個非負(fù)值,就獲得自旋鎖;否則就算作失敗。我們看到lock字段的值由Ox00ffffff到0x00000000要減多少次才可能出現(xiàn)負(fù)值,所以幾乎很難出現(xiàn)調(diào)用_read_lock_failed()函數(shù)的情況。該函數(shù)原子地增加lock字段以取消由read_lock宏執(zhí)行的遞減操作,然后循環(huán),直到lock字段變?yōu)檎龜?shù)(大于或等于0)。接下來,_read_lock_failed()又試圖獲取自旋鎖(正好在cmpl指令之后,另一個內(nèi)核控制路徑可能為寫獲取自旋鎖)。釋放讀自旋鎖是相當(dāng)簡單的,因為
41、read_unlock宏只需要使用匯編語言指令簡單地增加lock字段的計數(shù)器: lock; incl rwlp->lock以減少讀者的計數(shù),然后調(diào)用preempt_enable()重新啟用內(nèi)核搶占。2 為寫獲取或釋放一個鎖write_lock宏實現(xiàn)的方式與spin_lock()和read_lock()相似。例如,如果支持內(nèi)核搶占,則該函數(shù)禁用內(nèi)核搶占并通過調(diào)用_raw_write_trylock()立即獲得鎖。如果該函數(shù)返回0,說明鎖已經(jīng)被占用,因此,該宏像前面博文描述的那樣重新啟用內(nèi)核搶占并開始忙等待循環(huán)。#define write_lock(loc
42、k) _write_lock(lock)void _lockfunc _write_lock(rwlock_t *lock) preempt_disable(); rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);_raw_write_try
43、lock()函數(shù)描述如下: int _raw_write_trylock(rwlock_t *lock) atomic_t *count = (atomic_t *)lock->lock; if (atomic_sub_and_test(0x01000000, count)
44、60; return 1; atomic_add(0x01000000, count); return 0; static _inline_ int atomic_sub_and_test(int i, atomic_t *v) unsigned char c; _asm_
45、_volatile_( LOCK "subl %2,%0; sete %1" :"=m" (v->counter), "=qm" (c) :"ir" (i), "m" (v->counter) : "memory");
46、160; return c;函數(shù)_raw_write_trylock()調(diào)用tomic_sub_and_test(0x01000000, count)從讀/寫自旋鎖lock->lock的值中減去0x01000000,從而清除未上鎖標(biāo)志(看見沒有?正好是第24位)。如果減操作產(chǎn)生0值(沒有讀者),則獲取鎖并返回1;否則,函數(shù)原子地在自旋鎖的值上加0x01000000,以取消減操作。釋放寫鎖同樣非常簡單,因為write_unlock宏只需使用匯編語言指令:lock; addl $0x01000000,rwlp把lock字段中的“未鎖”標(biāo)識置位,然后再調(diào)用preempt_enable()。順序
47、鎖 分類: 瘋狂內(nèi)核之同步與互斥 2010-05-19 14:14 217人閱讀 評論(0) 收藏 舉報 當(dāng)使用讀/寫自旋鎖時,內(nèi)核控制路徑發(fā)出的執(zhí)行read_lock或write_lock操作的請求具有相同的優(yōu)先權(quán):讀者必須等待,直到寫操作完成。同樣地,寫者也必須等待,直到讀操作完成。Linux 2.6中引入了順序鎖(seqlock),它與讀/寫自旋鎖非常相似,只是它為寫者賦予了較高的優(yōu)先級:事實上,即使在讀者正在讀的時候也允許寫者繼續(xù)運行。這種策略的好處是寫者永遠(yuǎn)不會等待讀(除非另外一個寫者正在寫),缺點是有些時候讀者不得不反復(fù)讀多次相同的數(shù)據(jù)直到它獲得有效的結(jié)果。每個順序鎖都是包括兩個字
48、段的seqlock_t結(jié)構(gòu):typedef struct unsigned sequence; spinlock_t lock; seqlock_t;一個類型為spinlock_t的lock字段和一個整型的sequence字段,第二個字段sequence是一個順序計數(shù)器。每個讀者都必須在讀數(shù)據(jù)前后兩次讀順序計數(shù)器,并檢查兩次讀到的值是否相同,如果不相同,說明新的寫者已經(jīng)開始寫并增加了順序計數(shù)器,因此暗示讀者剛讀到的數(shù)據(jù)是無效的。通過把SEQLOCK_UNLOCKED賦給變量seqlock_t或執(zhí)行seqlock_init
49、宏,把seqlock_t變量初始化為“未上鎖”,并把sequence設(shè)為0:#define _SEQLOCK_UNLOCKED(lockname) / 0, _SPIN_LOCK_UNLOCKED(lockname) #define SEQLOCK_UNLOCKED / _SEQLOCK_UNLOCKED(old_style_seqlock_init)# define _SPIN_LOCK_UNLOCKED(locknam
50、e) / (spinlock_t) .raw_lock = _RAW_SPIN_LOCK_UNLOCKED, / SPIN_DEP_MAP_INIT(lockname) #define _RAW_SPIN_LOCK_UNLOCKED 1 寫者通過調(diào)用write_seq
51、lock()和write_sequnlock()獲取和釋放順序鎖。write_seqlock()函數(shù)獲取seqlock_t數(shù)據(jù)結(jié)構(gòu)中的自旋鎖,然后使順序計數(shù)器sequence加1;write_sequnlock()函數(shù)再次增加順序計數(shù)器sequence,然后釋放自旋鎖。這樣可以保證寫者在整個寫的過程中,計數(shù)器sequence的值是奇數(shù),并且當(dāng)沒有寫者在改變數(shù)據(jù)的時候,計數(shù)器的值是偶數(shù)。讀者進(jìn)程執(zhí)行下面的臨界區(qū)代碼: unsigned int seq; do
52、60; seq = read_seqbegin(&seqlock); /* . CRITICAL REGION . */ while (read_seqretry(&seqlock, seq);read_seqbegin()返回順序鎖的當(dāng)前順序號;如果局部變量seq的值是奇數(shù)(寫者在read_seqbegin()函數(shù)被調(diào)用后,正更新數(shù)據(jù)結(jié)構(gòu)),或seq的值與順序鎖的順序計數(shù)器的當(dāng)前值不匹配(當(dāng)讀者正執(zhí)行臨界區(qū)代碼時,寫者開始工作),read_seq
53、retry()就返回1:static _always_inline int read_seqretry(const seqlock_t *sl, unsigned iv) smp_rmb(); return (iv & 1) | (sl->sequence iv);注意在順序鎖機(jī)制里,讀者可能反復(fù)讀多次相同的數(shù)據(jù)直到它獲得有效的結(jié)果(read_seqretry返回0)。另外,當(dāng)讀者進(jìn)入臨界區(qū)時,不必禁用內(nèi)核搶占;另一方面,由寫者獲取自旋鎖,所以它進(jìn)入臨界區(qū)時自動禁用內(nèi)核搶占。并不是每一種資源都可以使用順序鎖來
54、保護(hù)。一般來說,必須在滿足下述條件時才能使用順序鎖:(1)被保護(hù)的數(shù)據(jù)結(jié)構(gòu)不包括被寫者修改和被讀者間接引用 的指針(否則,寫者可能在讀者的眼皮子底下就修改指針)。(2)讀者的臨界區(qū)代碼沒有副作用(否則,多個讀者的操作會與單獨的讀操作有不同的結(jié)果)。此外,讀者的臨界區(qū)代碼應(yīng)該簡短,而且寫者應(yīng)該不常獲取順序鎖,否則,反復(fù)的讀訪問會引起嚴(yán)重的開銷。在Linux 2.6中,使用順序鎖主要是保護(hù)一些與系統(tǒng)時間處理相關(guān)的數(shù)據(jù)結(jié)構(gòu)。RCU機(jī)制 分類: 瘋狂內(nèi)核之同步與互斥 2010-05-19 14:46 338人閱讀 評論(0) 收藏 舉報 讀-拷貝-更新(RCU)是為了保護(hù)在多數(shù)情況下被多個CPU讀的數(shù)
55、據(jù)結(jié)構(gòu)而設(shè)計的另一種同步技術(shù)。RCU允許多個讀者和寫者并發(fā)執(zhí)行(相對于只允許一個寫者執(zhí)行的順序鎖有了改進(jìn))。而且,RCU是不使用鎖的,就是說,它不使用被所有CPU共享的鎖或計數(shù)器,在這一點上與讀/寫自旋鎖和順序鎖(由于高速緩存行竊用和失效而有很高的開銷)相比RCU具有更大的優(yōu)勢。RCU是如何不使用共享數(shù)據(jù)結(jié)構(gòu)而令人驚訝地實現(xiàn)多個CPU同步呢?其關(guān)鍵的思想包包括限制RCP的范圍的兩個約束條件,這個是重中之重,如下所述:1. RCU只保護(hù)被動態(tài)分配并通過指針引用的數(shù)據(jù)結(jié)構(gòu)。2. 在被RCU保護(hù)的臨界區(qū)中,任何內(nèi)核控制路徑都不能睡眠。當(dāng)內(nèi)核控制路徑要讀取被RCU保護(hù)的數(shù)據(jù)結(jié)構(gòu)時,執(zhí)行宏rcu_rea
56、d_lock(),它僅僅是preempt_disable():#define rcu_read_lock() / do / preempt_disable(); / _acquire(RCU); / while(0)接下來,讀者間接引用該數(shù)據(jù)結(jié)構(gòu)指針?biāo)鶎?yīng)的內(nèi)存單元并開始讀這個數(shù)據(jù)結(jié)構(gòu)。正如在前面所強(qiáng)調(diào)的,讀者在完成對數(shù)據(jù)結(jié)構(gòu)的讀操作之前,是不能睡眠的。最后,用等同于preempt_enable()的宏rcu_read_unlock()標(biāo)記臨界區(qū)的結(jié)束:#define rcu_read_unlock() / do / _release(RCU); / preempt_enable(); /
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 賓館短租房合同模板
- 運營場地合同模板
- 石土方工程合同模板
- 房屋贈與比例合同模板
- 酒店酒水采購合同模板
- 杭州商鋪房租合同模板
- 溫泉施工合同模板
- 用工合同模板 cdr
- 轉(zhuǎn)按揭房貸合同模板
- 專用醫(yī)療器械購買合同:2024年標(biāo)準(zhǔn)版版
- 2024河南鄭州熱力集團(tuán)限公司招聘易考易錯模擬試題(共200題)試卷后附參考答案
- 護(hù)理綜述論文答辯
- 全國職業(yè)院校技能大賽高職組(供應(yīng)鏈管理賽項)備賽試題庫(含答案)
- 2024湖南長沙市人力社保局所屬事業(yè)單位招聘歷年(高頻重點復(fù)習(xí)提升訓(xùn)練)共500題附帶答案詳解
- 防洪監(jiān)理實施細(xì)則
- HG∕T 2469-2011 立式砂磨機(jī) 標(biāo)準(zhǔn)
- 化工企業(yè)重大事故隱患判定標(biāo)準(zhǔn)培訓(xùn)考試卷(后附答案)
- 河南省南陽市2023-2024學(xué)年高一上學(xué)期期中考試英語試題
- 上海市信息科技學(xué)科初中學(xué)業(yè)考試試卷及評分標(biāo)準(zhǔn)
- 2023遼寧公務(wù)員考試《行測》真題(含答案及解析)
- 冀教版數(shù)學(xué)七年級上下冊知識點總結(jié)
評論
0/150
提交評論