www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]文章底部有推薦有關(guān)嵌入式的學(xué)習(xí)教程,韋老師良心之作,積累項(xiàng)目經(jīng)驗(yàn),業(yè)界口碑非常好。 (1)什么是內(nèi)核同步 所謂的內(nèi)核同步就是對(duì)共享資源進(jìn)行保護(hù),防止并發(fā)訪問(wèn)。 如果有多個(gè)執(zhí)行線程(指任何正在執(zhí)行的代碼實(shí)例,比如一個(gè)在內(nèi)核執(zhí)行的進(jìn)程, 一個(gè)中斷處理程

文章底部有推薦有關(guān)嵌入式的學(xué)習(xí)教程,韋老師良心之作,積累項(xiàng)目經(jīng)驗(yàn),業(yè)界口碑非常好。


(1)什么是內(nèi)核同步
所謂的內(nèi)核同步就是對(duì)共享資源進(jìn)行保護(hù),防止并發(fā)訪問(wèn)。
如果有多個(gè)執(zhí)行線程(指任何正在執(zhí)行的代碼實(shí)例,比如一個(gè)在內(nèi)核執(zhí)行的進(jìn)程,
一個(gè)中斷處理程序,或一個(gè)內(nèi)核線程)同時(shí)訪問(wèn)和操作共享的數(shù)據(jù),
就有可能造成進(jìn)程之間互相覆蓋共享數(shù)據(jù),造成被訪問(wèn)數(shù)據(jù)處于不一致的情況。
這種錯(cuò)誤很難跟蹤和調(diào)試,但非常重要。

要做到對(duì)共享資源的恰當(dāng)保護(hù)是很困難的。

a.linux2.0以前的時(shí)代
在多年前,linux還沒(méi)有支持對(duì)稱多處理器SMP的時(shí)候,避免并發(fā)數(shù)據(jù)訪問(wèn)相對(duì)簡(jiǎn)單。
在單處理器的時(shí)候,只有在中斷發(fā)生的時(shí)候,或是在內(nèi)核代碼顯式地請(qǐng)求重新調(diào)度(調(diào)用schedule())時(shí),數(shù)據(jù)才可能被并發(fā)訪問(wèn)。

b.linux2.0以后的時(shí)代
從2.0開(kāi)始,linux開(kāi)始支持SMP.
此時(shí)如果不加保護(hù),運(yùn)行在兩個(gè)不同處理器上的內(nèi)核代碼完全可能在同一時(shí)刻并發(fā)訪問(wèn)共享數(shù)據(jù)。
到2.6時(shí),linux已經(jīng)發(fā)展成搶占式內(nèi)核,
在不加保護(hù)的時(shí)候,調(diào)度程序可以在任何時(shí)刻搶占正在運(yùn)行的內(nèi)核代碼,重新調(diào)度其他的進(jìn)程運(yùn)行。

隨著內(nèi)核的發(fā)展,共享數(shù)據(jù)的保護(hù)已經(jīng)成為驅(qū)動(dòng)開(kāi)發(fā)中最困難的問(wèn)題之一,而這些問(wèn)題在用戶應(yīng)用程序中并不常見(jiàn)。

(2)臨界區(qū)和競(jìng)爭(zhēng)條件
a.臨界區(qū)(critical region)
所謂臨界區(qū)就是訪問(wèn)和操作共享數(shù)據(jù)的代碼段。
因?yàn)槎鄠€(gè)執(zhí)行線程并發(fā)訪問(wèn)同一個(gè)資源通常是不安全的,所以程序員必須保證這些代碼段原子地執(zhí)行,
也就是說(shuō),代碼在執(zhí)行前不可被打斷,就如同整個(gè)臨界區(qū)是一個(gè)不可分割的指令一樣。

b.競(jìng)爭(zhēng)條件(race condition)
如果發(fā)生了兩個(gè)執(zhí)行線程處于同一個(gè)臨界區(qū)的情況,我們稱這就是一個(gè)競(jìng)爭(zhēng)條件。
這是程序包含的一個(gè)bug。競(jìng)爭(zhēng)引起的錯(cuò)誤很難重現(xiàn),所以非常難調(diào)試。

c.同步(synchronization)
避免并發(fā)和防止競(jìng)爭(zhēng)條件就被稱為同步。

d.單個(gè)變量形成的臨界區(qū)
一個(gè)非常簡(jiǎn)單的共享資源:
int i; /* 共享資源,全局整型變量 */
...
i++;  /* 臨界區(qū),對(duì)共享資源的操作 */

這個(gè)臨界區(qū)可以轉(zhuǎn)化成下面的機(jī)器指令:
*得到當(dāng)前變量i的值并且拷貝到一個(gè)寄存器
*將寄存器中的值加1
*把i的新值寫(xiě)回到內(nèi)存中

如果有兩個(gè)執(zhí)行線程同時(shí)進(jìn)入臨界區(qū),
假設(shè)i的初始值為7,我們期望的結(jié)果如下:
線程1         線程2
獲得i(7)      -
增加i(7->8)   -
寫(xiě)回i(8)      -
             獲得i(8)
             增加i(8->9)
             寫(xiě)回i(9)

實(shí)際的執(zhí)行結(jié)果卻可能是:
線程1         線程2
獲得i(7)      -
-            獲得i(7)
增加i(7->8)   -
-            增加i(7->8)
寫(xiě)回i(8)      -
-            寫(xiě)回i(8) 

e.如何處理上面的臨界區(qū)
這種是最簡(jiǎn)單的競(jìng)爭(zhēng)條件,只要把操作指令變成原子的就可以了。
多數(shù)處理器都提供了指令來(lái)原子地讀變量,增加變量然后再寫(xiě)回變量。
如果使用原子變量,唯一可能的結(jié)果就是:
線程1         線程2
增加i(7->8)   -
-            增加i(8->9)
或者是:
線程1         線程2
-            增加i(7->8)
增加i(8->9)   -
兩個(gè)原子操作交錯(cuò)執(zhí)行更本就不可能發(fā)生,
因?yàn)樘幚砥鲿?huì)從物理上確保這種不可能。

(3)加鎖
當(dāng)涉及到對(duì)數(shù)據(jù)結(jié)構(gòu)的操作時(shí),比如對(duì)鏈表的處理時(shí),
就不可能僅通過(guò)原子指令來(lái)保證同步,此時(shí),需要一種鎖機(jī)制。
程序中的鎖機(jī)制就像日常生活中的門鎖,門后的房間就是臨界區(qū)。
房間中同一時(shí)間只能有一個(gè)線程。

任何要訪問(wèn)隊(duì)列的代碼首先要占住相應(yīng)的鎖,這樣該鎖就能阻止來(lái)自其他執(zhí)行線程的并發(fā)訪問(wèn):
線程1          線程2
試圖鎖定隊(duì)列    試圖鎖定隊(duì)列
成功:獲得鎖    失敗:等待...
訪問(wèn)隊(duì)列...    等待...
為隊(duì)列解除鎖    等待...
...           成功:獲得鎖
              訪問(wèn)隊(duì)列...
              為隊(duì)列解除鎖

鎖的使用是自愿的,非強(qiáng)制的,它完全屬于一種編程者自選的編程手段。
鎖有多種形式,而且加鎖的粒度范圍也各不相同。
linux實(shí)現(xiàn)了幾種不同的鎖機(jī)制,
各種鎖機(jī)制之間的區(qū)別主要在于當(dāng)鎖被爭(zhēng)用時(shí)的行為:
一些鎖被爭(zhēng)用時(shí)會(huì)簡(jiǎn)單地進(jìn)行忙等待(spinlock)
一些鎖會(huì)使當(dāng)前任務(wù)睡眠直到鎖可用為止(semaphore)

(4)是什么造成了并發(fā)執(zhí)行
a.用戶空間的并發(fā)原因
用戶空間之所以需要同步,是因?yàn)橛脩舫绦驎?huì)被調(diào)度程序搶占和重新調(diào)度。
在單cpu上,并發(fā)操作并不是真的同時(shí)發(fā)生,
而是交錯(cuò)執(zhí)行,稱為偽并發(fā)。
如果是SMP系統(tǒng),兩個(gè)進(jìn)程就可以真正在臨界區(qū)中同時(shí)執(zhí)行了。這稱為真并發(fā)。

用戶空間可能產(chǎn)生并發(fā)的地方有:
*共享內(nèi)存
同一個(gè)進(jìn)程的兩個(gè)可執(zhí)行線程,訪問(wèn)共享的內(nèi)存時(shí)可能因?yàn)楸徽{(diào)度程序搶占后發(fā)生重新調(diào)度而并發(fā)

*信號(hào)
信號(hào)處理是異步的,如果信號(hào)處理程序和進(jìn)程的其他部分共享數(shù)據(jù),則有可能并發(fā)

b.內(nèi)核空間的并發(fā)原因
*中斷
中斷幾乎可以在任何時(shí)刻異步發(fā)生,也就可能隨時(shí)打斷當(dāng)前正在執(zhí)行的代碼

*軟中斷和tasklet
內(nèi)核能在任何時(shí)刻喚醒或調(diào)度軟中斷和tasklet,打斷當(dāng)前正在執(zhí)行的代碼

*內(nèi)核搶占
因?yàn)閮?nèi)核具有搶占性,所以內(nèi)核中的任務(wù)可能被另一個(gè)任務(wù)搶占

*睡眠及與用戶空間的同步
睡眠可能導(dǎo)致用戶進(jìn)程切換

*對(duì)稱多處理SMP
多個(gè)處理器可以同時(shí)執(zhí)行代碼

內(nèi)核開(kāi)發(fā)者必須理解這些并發(fā)執(zhí)行的原因,并為其做好準(zhǔn)備。
注意!辨認(rèn)出真正需要共享的數(shù)據(jù)和相應(yīng)的臨界區(qū),才是真正有挑戰(zhàn)性的地方。
在編寫(xiě)代碼的開(kāi)始階段就要設(shè)計(jì)出恰當(dāng)?shù)逆i,而不是事后才想到。

(5)要保護(hù)些什么
找出哪些數(shù)據(jù)需要保護(hù)是關(guān)鍵所在。
基本上除了執(zhí)行線程的內(nèi)部數(shù)據(jù)不需要鎖,其他所有的數(shù)據(jù)都可能需要鎖保護(hù)。
加鎖經(jīng)驗(yàn):
如果有其他執(zhí)行線程可以訪問(wèn)某些數(shù)據(jù),那么就給這些數(shù)據(jù)加上某種形式的鎖。
記??!要給數(shù)據(jù)而不是代碼加鎖。

內(nèi)核的配置選項(xiàng)
CONFIG_SMP
可以選擇不支持smp。許多加鎖問(wèn)題在單處理器上是不存在的。
如果在內(nèi)核配置時(shí)選擇了CONFIG_SMP,則不必要的代碼就不會(huì)被編入針對(duì)單處理器的內(nèi)核映像

CONFIG_PREEMPT
配置內(nèi)核是否支持搶占。

在你編寫(xiě)內(nèi)核代碼時(shí),要問(wèn)自己下面這些問(wèn)題:
a.這個(gè)數(shù)據(jù)是不是全局的?
除了當(dāng)前的線程外,其他線程能不能訪問(wèn)它?

b.這個(gè)數(shù)據(jù)會(huì)不會(huì)在進(jìn)程上下文和中斷上下文中共享?
它是不是要在兩個(gè)不同的中斷處理程序中共享?

c.進(jìn)程在訪問(wèn)數(shù)據(jù)時(shí)可不可能被搶占?
被調(diào)度的新程序會(huì)不會(huì)訪問(wèn)同一數(shù)據(jù)?

d.當(dāng)前進(jìn)程是不是會(huì)睡眠(阻塞)在某些資源上?
如果是,它會(huì)讓共享數(shù)據(jù)處于何種狀態(tài)?

e.如果這個(gè)函數(shù)又在另一個(gè)處理器上被調(diào)度將會(huì)發(fā)生什么?

f.你要對(duì)這些代碼做什么?

簡(jiǎn)言之,幾乎訪問(wèn)所有的內(nèi)核全局變量和共享數(shù)據(jù)都需要某種形式的同步方法。

(6)死鎖
死鎖的產(chǎn)生需要一定的條件:
需要一個(gè)或多個(gè)執(zhí)行線程和一個(gè)或多個(gè)資源,每個(gè)線程都在等待某個(gè)已經(jīng)被占用的資源。
例如交通路口的擁堵。

a.自死鎖
如果代碼已經(jīng)獲得了某個(gè)鎖,又再次去獲得它,就會(huì)造成自死鎖。
如:
線程1
獲得鎖
再次試圖獲得鎖
等待鎖重新可用

b.ABBA死鎖
線程1              線程2
獲得A鎖            獲得B鎖
試圖獲得B鎖        試圖獲得A鎖
等待B鎖            等待A鎖

c.避免死鎖的簡(jiǎn)單規(guī)則
*加鎖的順序是關(guān)鍵
使用嵌套的鎖時(shí)必須保證以相同的順序獲得鎖。
比如上面的ABBA死鎖,如果所有進(jìn)程都按照先獲得A鎖再獲得B鎖的順序,就不會(huì)死鎖了

*不要重復(fù)請(qǐng)求同一個(gè)鎖
*越復(fù)雜的加鎖方案越有可能造成死鎖--設(shè)計(jì)應(yīng)力求簡(jiǎn)單
*盡管釋放鎖的順序和死鎖是無(wú)關(guān)的,但最好還是以獲得鎖的相反順序來(lái)釋放鎖。

/*********************
 * 內(nèi)核同步方法
 ********************/
 
前面討論了競(jìng)爭(zhēng)如何產(chǎn)生以及怎么去解決。
下面將介紹linux為解決競(jìng)爭(zhēng)問(wèn)題而提供的同步方法
(1)原子整數(shù)操作
原子操作可以保證指令以原子的方式運(yùn)行--執(zhí)行過(guò)程不能被打斷。
原子操作把讀取和改變變量的行為包含在一個(gè)單步中執(zhí)行,
從而避免了競(jìng)爭(zhēng),如:
線程1             線程2
atomic i(7->8)   -
-                atomic i(8->9)

內(nèi)核提供了針對(duì)整數(shù)和單獨(dú)的位進(jìn)行的原子操作。
針對(duì)整數(shù)的原子操作只能對(duì)atomic_t類型的數(shù)據(jù)進(jìn)行訪問(wèn)。
定義在<asm/atomic.h>
typedef struct { volatile int counter; } atomic_t;
a.定義
atomic_t t;
atomic_t u = ATOMIC_INIT(0); /* 定義u并初始化為0 */
b.操作
都定義在<asm/atomic.h>中。
原子操作通常是內(nèi)聯(lián)函數(shù),往往通過(guò)內(nèi)嵌匯編指令來(lái)實(shí)現(xiàn)。
int atomic_read(atomic_t v);
原子地讀取變量v
void atomic_set(atomic_t *v, int i);     // v = i;
void atomic_add(int i, atomic_t *v);     // v += i;
void atomic_sub(int i, atomic_t *v);     // v -= i;
void atomic_inc(atomic_t *v);            // v += 1;
void atomic_dec(atomic_t *v);            // v -= 1;
原子地加減1
int atomic_sub_and_test(int i, atomic_t *v)
原子地從v減去i,如果結(jié)果等于0返回真,否則返回假
int atomic_add_negative(int i, atomic_t *v)
結(jié)果為負(fù)數(shù)返回真,否則返回假
int atomic_dec_and_test(atomic_t *v);    // i -= 1; i == 0;
int atomic_inc_and_test(atomic_t *v);    // i += 1; i == 0;
結(jié)果等于0返回真,否則返回假
(2)原子位操作
定義在<asm/bitops.h>。這些函數(shù)針對(duì)某個(gè)普通的內(nèi)存地址。
可用的位操作:
void set_bit(nr, void *addr);
設(shè)置addr指向的數(shù)據(jù)項(xiàng)的第nr位
*addr |= (0x1 << nr);
void clear_bit(nr, void *addr);
清除addr指向的數(shù)據(jù)項(xiàng)的第nr位
*addr &= ~(0x1 << nr);
test_bit(nr, void *addr);
返回指定位的當(dāng)前值
*addr & (0x1 << nr);
int test_and_set_bit(nr, void *addr);
設(shè)置nr位的同時(shí)返回原來(lái)的值

例子:
unsigned long word = 0;

set_bit(0, &word); /* 原子地設(shè)定第0位 */
set_bit(1, &word); /* 原子地設(shè)定第1位 */
clear_bit(1, &word); /* 原子地清空第1位 */
change_bit(0, &word); /* 原子地翻轉(zhuǎn)第0位 */

/* 原子地設(shè)置第0位并返回設(shè)置前的值(0) */
if(test_and_set_bit(0, &word){
  /* 不為真 */
}

word = 7;  /* 合法 */

內(nèi)核還提供了一組非原子位操作函數(shù),名字前面多了兩個(gè)下劃線。如__test_bit()
如果不需要原子性操作,比如已經(jīng)用鎖保護(hù)了數(shù)據(jù),
用這些非原子的位操作可能更快。

(3)原子性與順序性的比較
原子性確保指令執(zhí)行期間不被打斷,要么全部執(zhí)行完,要么不執(zhí)行。
順序性確保指令的執(zhí)行順序不改變。通過(guò)屏障指令(barrier)來(lái)保證。
能使用原子操作的時(shí)候,就盡量不要使用復(fù)雜的加鎖機(jī)制。

(4)spinlock自旋鎖
原子操作只能針對(duì)整數(shù)和位,面對(duì)更復(fù)雜的臨界區(qū),
比如從一個(gè)數(shù)據(jù)結(jié)構(gòu)中移出數(shù)據(jù),處理完后再加入到另一個(gè)數(shù)據(jù)結(jié)構(gòu)中。
這種情況就需要更復(fù)雜的同步方法--鎖來(lái)提供保護(hù)。

linux內(nèi)核中最常見(jiàn)的鎖是自旋鎖(spin lock)。
自旋鎖最多只能被一個(gè)可執(zhí)行線程持有,等待鎖的進(jìn)程采用忙循環(huán)等待(只針對(duì)smp)。
因?yàn)槊ρh(huán)很消耗處理器時(shí)間,所以自旋鎖不能被長(zhǎng)時(shí)間持有。
持有自旋鎖的時(shí)間最好小于完成兩次上下文切換的時(shí)間,
如果時(shí)間太長(zhǎng),就需要采用另外的加鎖方式。

自旋鎖定義在<asm/spinlock.h>和<linux/spinlock.h>

自旋鎖可以在中斷處理程序中使用。
在這種情況下,其他代碼要獲得鎖時(shí)必須首先關(guān)閉中斷。
在單處理器上,加鎖操作只是簡(jiǎn)單地把內(nèi)核搶占關(guān)閉。

等待自旋鎖時(shí)程序不會(huì)睡眠,同樣,一旦擁有了spinlock,代碼也不能睡眠。
此時(shí),必須注意每個(gè)調(diào)用的系統(tǒng)函數(shù),因?yàn)橛行┖瘮?shù)是可能導(dǎo)致睡眠的(如kmallspin_unlock_irqstoreoc)。
可以選定CONFIG_DEBUG_SPINLOCK選項(xiàng),打開(kāi)spinlock的調(diào)試功能

a.spinlock的初始化
靜態(tài)
spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
動(dòng)態(tài)
void spin_lock_init(spinlock_t *lock);

b.加鎖函數(shù)
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);

如果我們的一個(gè)自旋鎖可以被中斷處理程序或者是中斷的下半部獲得,則必須使用禁止中斷的spin_lock形式。

c.解鎖函數(shù)
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);

d.非阻塞的自旋鎖操作
int spin_trylock(spinlock_t *lock);
int spin_trylock_bh(spinlock_t *lock);
成功(即獲得鎖)時(shí)返回非零,否則返回0

(5)讀取者/寫(xiě)入者自旋鎖(reader/writer)
有時(shí)候,鎖的用途可以明確分為讀取和寫(xiě)入。比如對(duì)鏈表的更新和檢索。
寫(xiě)操作必須要求并發(fā)保護(hù),但多個(gè)并發(fā)的讀操作是安全的。
這樣可以提高鎖的使用效率。定義在<linux/spinlock.h>

a.初始化
靜態(tài)
rwlock_t my_rwlock = RW_LOCK_UNLOCKED;
動(dòng)態(tài)
rwlock_t my_rwlock;
rwlock_init(&my_rwlock);

b.加鎖
read/write_lock()
read/write_lock_irq()
read/write_lock_irqsave()
read/write_lock_bh()

c.解鎖
read/write_unlock()
read/write_unlock_irq()
read/write_unlock_irqsave()
read/write_unlock_bh()

d.其他
write_trylock()
rw_is_locked()

e.使用方式
rwlock_t my_rwlock = RW_LOCK_UNLOCKED;

讀者
read_lock(&my_rwlock);
/* 臨界區(qū)(只讀) */
read_unlock(&my_rwlock);

寫(xiě)者
write_lock(&my_rwlock);
/* 臨界區(qū)(讀寫(xiě)) */
write_unlock(&my_rwlock);

通常,讀鎖和寫(xiě)鎖位于完全分開(kāi)的代碼中。不能把一個(gè)讀鎖升級(jí)為寫(xiě)鎖。如:
read_lock(&my_rwlock);
...
write_lock(&my_rwlock);
這會(huì)造成死鎖。
如果代碼不能清晰分成讀和寫(xiě)兩部分,那么就用普通的spinlock就可以了。

注意!讀/寫(xiě)者鎖機(jī)制要更照顧讀者。
當(dāng)讀鎖被持有時(shí),寫(xiě)者必須等待,直到所有的讀者釋放鎖,而其他的讀者卻可以繼續(xù)獲得鎖。
這樣,大量讀者必定會(huì)使刮起的寫(xiě)者處于饑餓狀態(tài)。

如果加鎖時(shí)間不長(zhǎng)并且代碼不會(huì)睡眠(比如中斷處理程序),利用自旋鎖是最佳方案;
如果加鎖時(shí)間很長(zhǎng)或者代碼在持有鎖時(shí)有可能睡眠,則最好用信號(hào)量來(lái)完成加鎖。

(6)信號(hào)量(semaphore)和互斥體
信號(hào)量(semaphore)和信號(hào)(signal)是完全不同的概念。
linux的信號(hào)量是一種睡眠鎖。
如果一個(gè)進(jìn)程a試圖獲得一個(gè)已經(jīng)被占用的信號(hào)量時(shí),該進(jìn)程將被送入一個(gè)等待隊(duì)列,然后睡眠。
持有信號(hào)量的進(jìn)程b將信號(hào)量釋放后,進(jìn)程a將被喚醒并獲得信號(hào)量。
信號(hào)量比自旋鎖能提供更好的處理器利用率,但信號(hào)量的開(kāi)銷更大。

信號(hào)量的特性
a.信號(hào)量適用于鎖會(huì)被長(zhǎng)期持有時(shí),因?yàn)槠溟_(kāi)銷比較大
b.只有在進(jìn)程上下文中才能獲得信號(hào)量,因?yàn)楂@取信號(hào)量時(shí)可能導(dǎo)致睡眠,不適用于中斷上下文
c.可以在持有信號(hào)量時(shí)去睡眠,因此可以在持有信號(hào)量的時(shí)候和用戶空間同步
d.不能在持有信號(hào)量的同時(shí)持有自旋鎖
e.信號(hào)量可以允許任意數(shù)量的鎖持有者,而自旋鎖在一個(gè)時(shí)刻只能有一個(gè)持有者。
只擁有一個(gè)持有者的信號(hào)量稱為互斥信號(hào)量

(7)信號(hào)量的實(shí)現(xiàn)
信號(hào)量的實(shí)現(xiàn)與體系結(jié)構(gòu)相關(guān),具體實(shí)現(xiàn)定義在<asm/semaphore.h>
<linux/semaphore.h>

a.信號(hào)量的聲明
靜態(tài)
static DECLARE_SEMAPHORE_GENERIC(name, count);
或聲明一個(gè)互斥信號(hào)量
static DECLARE_MUTEX(name);

動(dòng)態(tài)
struct semaphore sem; /*信號(hào)量常作為一個(gè)大的結(jié)構(gòu)體中的一部分*/
sema_init(&sem, count);
init_MUTEX(&sem); /* 初始化互斥信號(hào)量 */
init_MUTEX_LOCKED(&sem); /*初始化后信號(hào)量就被鎖定 */

b.獲得信號(hào)量
void down(struct semaphore *sem);
減小信號(hào)量的值。函數(shù)返回后獲得信號(hào)量

int down_interruptible(struct semaphore *sem);;
在等待信號(hào)量時(shí),可以被用戶空間程序通過(guò)信號(hào)中斷。
這是我們常用的版本。
如果操作被中斷,則返回非零值,調(diào)用者無(wú)法獲得信號(hào)量。
注意!調(diào)用時(shí)始終要檢查返回值。

int down_trylock(struct semaphore *sem);
不會(huì)休眠,如果不能獲得信號(hào)量,立即返回一個(gè)非零值

c.釋放信號(hào)量
viod up(struct semaphore *sem);

linux也提供了讀取者/寫(xiě)入者信號(hào)量。
#include <linux/rwsem.h>
struct rw_semaphore;

(9)completion機(jī)制
在內(nèi)核編程中常見(jiàn)的一種模式是:
在當(dāng)前線程之外初始化某個(gè)活動(dòng),然后等待該活動(dòng)的結(jié)束。
這個(gè)活動(dòng)可能是創(chuàng)建一個(gè)新的內(nèi)核線程或者新的用戶空間進(jìn)程,
對(duì)一個(gè)已有進(jìn)程的某個(gè)請(qǐng)求,或者某種類型的硬件活動(dòng)等等。
可以利用信號(hào)量對(duì)兩個(gè)任務(wù)進(jìn)行同步。例如:
在任務(wù)1中
struct semaphore sem;
init_MUTEX_LOCKED(&sem);
start_external_task(&sem);
down(&sem);

在任務(wù)2中
首先down(&sem),這樣任務(wù)1就會(huì)在sem上等待;
任務(wù)2完成后,調(diào)用up(&sem),任務(wù)1恢復(fù)執(zhí)行

用信號(hào)量來(lái)完成這一工作并不太有效,因此內(nèi)核提供了completion機(jī)制(出現(xiàn)在2.4.7)來(lái)完成這一工作。

a.創(chuàng)建completion
#include <linux/completion.h>
靜態(tài)
DECLARE_COMPLETION(my_completion);
動(dòng)態(tài)
struct completion my_completion;
init_completion(&my_completion);

b.等待completion
void wait_for_completion(struct completion *c);
執(zhí)行一個(gè)非中斷的等待,用戶空間無(wú)法通過(guò)signal來(lái)中斷這個(gè)進(jìn)程。

c.完成completion
void complete(struct completion *);
發(fā)信號(hào)喚醒任何等待任務(wù)

(2)如何禁止內(nèi)核搶占
由于內(nèi)核是搶占性的,內(nèi)核中的進(jìn)程在任何時(shí)刻都可能停下來(lái)被更高優(yōu)先級(jí)的進(jìn)程搶占。
有時(shí)候需要把這一特性關(guān)閉。
用戶驅(qū)動(dòng)直接關(guān)閉內(nèi)核搶占的情況不多,但一些內(nèi)核機(jī)制的內(nèi)部需要這一功能。
比如單cpu系統(tǒng)上的spinlock鎖,
spin_lock的內(nèi)部并沒(méi)有忙等待,而只是關(guān)閉了內(nèi)核搶占。

a.搶占的相關(guān)函數(shù)
*preempt_disable()
增加搶占計(jì)數(shù)值,從而禁止內(nèi)核搶占。
如果搶占計(jì)數(shù)為0則內(nèi)核可以進(jìn)行搶占,如果為1或更大的數(shù)值,則禁止搶占

*preempt_enable()
減少搶占計(jì)數(shù),并當(dāng)該值降為0時(shí)檢查和執(zhí)行被掛起的需調(diào)度的任務(wù)

*preempt_enable_no_resched()
激活內(nèi)核搶占,但不檢查被掛起的需調(diào)度的任務(wù)

*preempt_count()
返回?fù)屨加?jì)數(shù)

b.每個(gè)cpu上的數(shù)據(jù)訪問(wèn)
int cpu;
/*禁止內(nèi)核搶占,并將cpu設(shè)置為當(dāng)前處理器 */
cpu=get_cpu();

對(duì)每個(gè)處理器的數(shù)據(jù)進(jìn)行操作

/*啟動(dòng)內(nèi)核搶占 */
put_cpu();

  另外,推薦嵌入式學(xué)習(xí)良心之作,韋東山老師嵌入式教程。


免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉