導航:首頁 > 操作系統 > linux信號燈

linux信號燈

發布時間:2023-02-12 16:15:43

A. linux進程間通信(互斥鎖、條件變數、讀寫鎖、文件鎖、信號燈)

為了能夠有效的控制多個進程之間的溝通過程,保證溝通過程的有序和和諧,OS必須提供一定的同步機制保證進程之間不會自說自話而是有效的協同工作。比如在 共享內存的通信方式中,兩個或者多個進程都要對共享的內存進行數據寫入,那麼怎麼才能保證一個進程在寫入的過程中不被其它的進程打斷,保證數據的完整性 呢?又怎麼保證讀取進程在讀取數據的過程中數據不會變動,保證讀取出的數據是完整有效的呢?

常用的同步方式有: 互斥鎖、條件變數、讀寫鎖、記錄鎖(文件鎖)和信號燈.

互斥鎖:

顧名思義,鎖是用來鎖住某種東西的,鎖住之後只有有鑰匙的人才能對鎖住的東西擁有控制權(把鎖砸了,把東西偷走的小偷不在我們的討論范圍了)。所謂互斥, 從字面上理解就是互相排斥。因此互斥鎖從字面上理解就是一點進程擁有了這個鎖,它將排斥其它所有的進程訪問被鎖住的東西,其它的進程如果需要鎖就只能等待,等待擁有鎖的進程把鎖打開後才能繼續運行。 在實現中,鎖並不是與某個具體的變數進行關聯,它本身是一個獨立的對象。進(線)程在有需要的時候獲得此對象,用完不需要時就釋放掉。

互斥鎖的主要特點是互斥鎖的釋放必須由上鎖的進(線)程釋放,如果擁有鎖的進(線)程不釋放,那麼其它的進(線)程永遠也沒有機會獲得所需要的互斥鎖。

互斥鎖主要用於線程之間的同步。

條件變數:

上文中提到,對於互斥鎖而言,如果擁有鎖的進(線)程不釋放鎖,其它進(線)程永遠沒機會獲得鎖,也就永遠沒有機會繼續執行後續的邏輯。在實際環境下,一 個線程A需要改變一個共享變數X的值,為了保證在修改的過程中X不會被其它的線程修改,線程A必須首先獲得對X的鎖。現在假如A已經獲得鎖了,由於業務邏 輯的需要,只有當X的值小於0時,線程A才能執行後續的邏輯,於是線程A必須把互斥鎖釋放掉,然後繼續「忙等」。如下面的偽代碼所示:

1.// get x lock

2.while(x

B. linux 信號燈中線程切換問題

(1)Posix標准中有有名信號燈和無名信號燈之分,對於有名信號燈,可以用sem_open來創建,其prototype是:

sem_t *sem_open(const char *name, int oflag);//打開已有的信號燈

sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned value);//一般是創建信號燈。

期中name是信號燈的名字, oflag是0, O_CREAT 或者 O_CREAT | O_EXCL, 如果指定O_CREAT, 那麼mode和value對應創建該信號的模式和初始值。 如果指定了O_EXCL, 而且該信號燈已經在系統中存在,那調用會出錯返回SEM_FAILED常量。 對於Linux內核來說,有名信號燈是很晚才加入內核中的,創建或是打開有名信號時候,應該指定」/semname「名字,對應的信號燈創建在/dev/shm目錄下,名字是/dev/shm/sem.semname. BTW, 用gcc/g++編譯實用信號燈功能的程序時候,應該引用librt庫,(e.g., g++ -lrt sem.cpp). 關閉已打開的信號燈,用sem_close(sem_t *sem). 關閉信號燈並不意味著系統會刪除它,要刪除一個信號燈,需要調用sem_unlink(sem_t *sem)。 有名信號燈一般是為了進程之間同步實用的。 無名信號燈,一般是為一個進程內的不同線程之間同步使用的。 創建無名信號燈的方法如下:

sem_t sem;

sem_init(&sem, int shared, unsigned int value);//初始化信號燈。

......

sem_destroy(&sem);//清除信號燈。

(2)信號燈的使用和狀態。

信號燈一般用來描述不同線程所共享的公共資源的數量,每一個信號燈都有一個叫做信號量的非負整數與之相連;信號量一般代表公共資源的數目,比如空閑列表中的緩沖區數目,視頻中讀入幀的數目,等等。對於一個線程可以用sem_wait, sem_post函數來改變一個信號燈的信號量。

sem_wait(sem_t &sem);

sem_wait的語義如下:

{

while(信號量==0)

等待; //此處線程被掛起,等待其他線程調用sem_post喚醒之。

信號量減1;

}

注意:測試信號量是否為零,和減一的操作是原子的,也就是說期間不會發生線程切換。

與sem_wait對應的調用是sem_post,語義如下:

{

信號量加1;

喚醒等待該信號量的線程;//調用sem_wait並等待的線程。

}

該操作也是原子的。

信號燈的狀態可以用sem_getvalue來查看。一般來說sem_wait和sem_post的調用不必在同一個線程內成對出現(象mutex那樣,lock/unlock要配對出現)。 一般的情形是這樣的,一個線程等待資源可用,調用sem_wait, 另外一個線程生成資源,然後調用sem_post,喚醒等待該資源的線程。因為信號燈所描述的是線程間公共資源,使用的時候一般和mutex一起使用,mutex保證訪問公共資源的線程排他性,信號燈表示資源的可用性。

C. linux內核同步問題

Linux內核設計與實現 十、內核同步方法

手把手教Linux驅動5-自旋鎖、信號量、互斥體概述

== 基礎概念: ==

並發 :多個執行單元同時進行或多個執行單元微觀串列執行,宏觀並行執行

競態 :並發的執行單元對共享資源(硬體資源和軟體上的全局變數)的訪問而導致的竟態狀態。

臨界資源 :多個進程訪問的資源

臨界區 :多個進程訪問的代碼段

== 並發場合: ==

1、單CPU之間進程間的並發 :時間片輪轉,調度進程。 A進程訪問列印機,時間片用完,OS調度B進程訪問列印機。

2、單cpu上進程和中斷之間並發 :CPU必須停止當前進程的執行中斷;

3、多cpu之間

4、單CPU上中斷之間的並發

== 使用偏向: ==

==信號量用於進程之間的同步,進程在信號量保護的臨界區代碼裡面是可以睡眠的(需要進行進程調度),這是與自旋鎖最大的區別。==

信號量又稱為信號燈,它是用來協調不同進程間的數據對象的,而最主要的應用是共享內存方式的進程間通信。本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取狀況。它負責協調各個進程,以保證他們能夠正確、合理的使用公共資源。它和spin lock最大的不同之處就是:無法獲取信號量的進程可以睡眠,因此會導致系統調度。

1、==用於進程與進程之間的同步==

2、==允許多個進程進入臨界區代碼執行,臨界區代碼允許睡眠;==

3、信號量本質是==基於調度器的==,在UP和SMP下沒有區別;進程獲取不到信號量將陷入休眠,並讓出CPU;

4、不支持進程和中斷之間的同步

5、==進程調度也是會消耗系統資源的,如果一個int型共享變數就需要使用信號量,將極大的浪費系統資源==

6、信號量可以用於多個線程,用於資源的計數(有多種狀態)

==信號量加鎖以及解鎖過程:==

sema_init(&sp->dead_sem, 0); / 初始化 /

down(&sema);

臨界區代碼

up(&sema);

==信號量定義:==

==信號量初始化:==

==dowm函數實現:==

==up函數實現:==

信號量一般可以用來標記可用資源的個數。

舉2個生活中的例子:

==dowm函數實現原理解析:==

(1)down

判斷sem->count是否 > 0,大於0則說明系統資源夠用,分配一個給該進程,否則進入__down(sem);

(2)__down

調用__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);其中TASK_UNINTERRUPTIBLE=2代表進入睡眠,且不可以打斷;MAX_SCHEDULE_TIMEOUT休眠最長LONG_MAX時間;

(3)list_add_tail(&waiter.list, &sem->wait_list);

把當前進程加入到sem->wait_list中;

(3)先解鎖後加鎖;

進入__down_common前已經加鎖了,先把解鎖,調用schele_timeout(timeout),當waiter.up=1後跳出for循環;退出函數之前再加鎖;

Linux內核ARM構架中原子變數的底層實現研究

rk3288 原子操作和原子位操作

原子變數適用於只共享一個int型變數;

1、原子操作是指不被打斷的操作,即它是最小的執行單位。

2、最簡單的原子操作就是一條條的匯編指令(不包括一些偽指令,偽指令會被匯編器解釋成多條匯編指令)

==常見函數:==

==以atomic_inc為例介紹實現過程==

在Linux內核文件archarmincludeasmatomic.h中。 執行atomic_read、atomic_set這些操作都只需要一條匯編指令,所以它們本身就是不可打斷的。 需要特別研究的是atomic_inc、atomic_dec這類讀出、修改、寫回的函數。

所以atomic_add的原型是下面這個宏:

atomic_add等效於:

result(%0) tmp(%1) (v->counter)(%2) (&v->counter)(%3) i(%4)

注意:根據內聯匯編的語法,result、tmp、&v->counter對應的數據都放在了寄存器中操作。如果出現上下文切換,切換機制會做寄存器上下文保護。

(1)ldrex %0, [%3]

意思是將&v->counter指向的數據放入result中,並且(分別在Local monitor和Global monitor中)設置獨占標志。

(2)add %0, %0, %4

result = result + i

(3)strex %1, %0, [%3]

意思是將result保存到&v->counter指向的內存中, 此時 Exclusive monitors會發揮作用,將保存是否成功的標志放入tmp中。

(4) teq %1, #0

測試strex是否成功(tmp == 0 ??)

(5)bne 1b

如果發現strex失敗,從(1)再次執行。

Spinlock 是內核中提供的一種比較常見的鎖機制,==自旋鎖是「原地等待」的方式解決資源沖突的==,即,一個線程獲取了一個自旋鎖後,另外一個線程期望獲取該自旋鎖,獲取不到,只能夠原地「打轉」(忙等待)。由於自旋鎖的這個忙等待的特性,註定了它使用場景上的限制 —— 自旋鎖不應該被長時間的持有(消耗 CPU 資源),一般應用在==中斷上下文==。

1、spinlock是一種死等機制

2、信號量可以允許多個執行單元進入,spinlock不行,一次只能允許一個執行單元獲取鎖,並且進入臨界區,其他執行單元都是在門口不斷的死等

3、由於不休眠,因此spinlock可以應用在中斷上下文中;

4、由於spinlock死等的特性,因此臨界區執行代碼盡可能的短;

==spinlock加鎖以及解鎖過程:==

spin_lock(&devices_lock);

臨界區代碼

spin_unlock(&devices_lock);

==spinlock初始化==

==進程和進程之間同步==

==本地軟中斷之間同步==

==本地硬中斷之間同步==

==本地硬中斷之間同步並且保存本地中斷狀態==

==嘗試獲取鎖==

== arch_spinlock_t結構體定義如下: ==

== arch_spin_lock的實現如下: ==

lockval(%0) newval(%1) tmp(%2) &lock->slock(%3) 1 << TICKET_SHIFT(%4)

(1)ldrex %0, [%3]

把lock->slock的值賦值給lockval;並且(分別在Local monitor和Global monitor中)設置獨占標志。

(2)add %1, %0, %4

newval =lockval +(1<<16); 相當於next+1;

(3)strex %2, %1, [%3]

newval =lockval +(1<<16); 相當於next+1;

意思是將newval保存到 &lock->slock指向的內存中, 此時 Exclusive monitors會發揮作用,將保存是否成功的標志放入tmp中。

(4) teq %2, #0

測試strex是否成功

(5)bne 1b

如果發現strex失敗,從(1)再次執行。

通過上面的分析,可知關鍵在於strex的操作是否成功的判斷上。而這個就歸功於ARM的Exclusive monitors和ldrex/strex指令的機制。

(6)while (lockval.tickets.next != lockval.tickets.owner)

如何lockval.tickets的next和owner是否相等。相同則跳出while循環,否則在循環內等待判斷;

* (7)wfe()和smp_mb() 最終調用#define barrier() asm volatile ("": : :"memory") *

阻止編譯器重排,保證編譯程序時在優化屏障之前的指令不會在優化屏障之後執行。

== arch_spin_unlock的實現如下: ==

退出鎖時:tickets.owner++

== 出現死鎖的情況: ==

1、擁有自旋鎖的進程A在內核態阻塞了,內核調度B進程,碰巧B進程也要獲得自旋鎖,此時B只能自旋轉。 而此時搶占已經關閉,(單核)不會調度A進程了,B永遠自旋,產生死鎖。

2、進程A擁有自旋鎖,中斷到來,CPU執行中斷函數,中斷處理函數,中斷處理函數需要獲得自旋鎖,訪問共享資源,此時無法獲得鎖,只能自旋,產生死鎖。

== 如何避免死鎖: ==

1、如果中斷處理函數中也要獲得自旋鎖,那麼驅動程序需要在擁有自旋鎖時禁止中斷;

2、自旋鎖必須在可能的最短時間內擁有

3、避免某個獲得鎖的函數調用其他同樣試圖獲取這個鎖的函數,否則代碼就會死鎖;不論是信號量還是自旋鎖,都不允許鎖擁有者第二次獲得這個鎖,如果試圖這么做,系統將掛起;

4、鎖的順序規則(a) 按同樣的順序獲得鎖;b) 如果必須獲得一個局部鎖和一個屬於內核更中心位置的鎖,則應該首先獲取自己的局部鎖 ;c) 如果我們擁有信號量和自旋鎖的組合,則必須首先獲得信號量;在擁有自旋鎖時調用down(可導致休眠)是個嚴重的錯誤的;)

== rw(read/write)spinlock: ==

加鎖邏輯:

1、假設臨界區內沒有任何的thread,這個時候任何的讀線程和寫線程都可以鍵入

2、假設臨界區內有一個讀線程,這時候信賴的read線程可以任意進入,但是寫線程不能進入;

3、假設臨界區有一個寫線程,這時候任何的讀、寫線程都不可以進入;

4、假設臨界區內有一個或者多個讀線程,寫線程不可以進入臨界區,但是寫線程也無法阻止後續的讀線程繼續進去,要等到臨界區所有的讀線程都結束了,才可以進入,可見:==rw(read/write)spinlock更加有利於讀線程;==

== seqlock(順序鎖): ==

加鎖邏輯:

1、假設臨界區內沒有任何的thread,這個時候任何的讀線程和寫線程都可以鍵入

2、假設臨界區內沒有寫線程的情況下,read線程可以任意進入;

3、假設臨界區有一個寫線程,這時候任何的讀、寫線程都不可以進入;

4、假設臨界區內只有read線程的情況下,寫線程可以理解執行,不會等待,可見:==seqlock(順序鎖)更加有利於寫線程;==

讀寫速度 CPU > 一級緩存 > 二級緩存 > 內存 ,因此某一個CPU0的lock修改了,其他的CPU的lock就會失效;那麼其他CPU就會依次去L1 L2和主存中讀取lock值,一旦其他CPU去讀取了主存,就存在系統性能降低的風險;

mutex用於互斥操作。

互斥體只能用於一個線程,資源只有兩種狀態(佔用或者空閑)

1、mutex的語義相對於信號量要簡單輕便一些,在鎖爭用激烈的測試場景下,mutex比信號量執行速度更快,可擴展

性更好,

2、另外mutex數據結構的定義比信號量小;、

3、同一時刻只有一個線程可以持有mutex

4、不允許遞歸地加鎖和解鎖

5、當進程持有mutex時,進程不可以退出。

• mutex必須使用官方API來初始化。

• mutex可以睡眠,所以不允許在中斷處理程序或者中斷下半部中使用,例如tasklet、定時器等

==常見操作:==

struct mutex mutex_1;

mutex_init(&mutex_1);

mutex_lock(&mutex_1)

臨界區代碼;

mutex_unlock(&mutex_1)

==常見函數:==

=

D. linux 信號燈和信號量的區別

信號量是與signal相關的內容,是進程間通信的一種方式,一個進程可以向另一個進程發送一個信號作為通知,除了signal系統調用外,相關內容還有:

SEE ALSO
kill(1), alarm(2), kill(2), killpg(2), pause(2), sigaction(2), signalfd(2), sigpending(2), sigprocmask(2), sigsuspend(2), bsd_signal(3), raise(3), sigin-
terrupt(3), sigqueue(3), sigsetops(3), sigvec(3), sysv_signal(3), signal(7)

信號量也是進程通信的一種方式,一般用於並發取得資源對應鎖或者其他互斥操作,除了semget系統調用外,相關內容還有:

SEE ALSO
semctl(2), semop(2), ftok(3), capabilities(7), sem_overview(7), svipc(7)

E. Linux信號量

信號量是包含一個非負整數型的變數,並且帶有兩個原子操作wait和signal。Wait還可以被稱為down、P或lock,signal還可以被稱為up、V、unlock或post。在UNIX的API中(POSIX標准)用的是wait和post。

對於wait操作,如果信號量的非負整形變數S大於0,wait就將其減1,如果S等於0,wait就將調用線程阻塞;對於post操作,如果有線程在信號量上阻塞(此時S等於0),post就會解除對某個等待線程的阻塞,使其從wait中返回,如果沒有線程阻塞在信號量上,post就將S加1.

由此可見,S可以被理解為一種資源的數量,信號量即是通過控制這種資源的分配來實現互斥和同步的。如果把S設為1,那麼信號量即可使多線程並發運行。另外,信號量不僅允許使用者申請和釋放資源,而且還允許使用者創造資源,這就賦予了信號量實現同步的功能。可見信號量的功能要比互斥量豐富許多。

POSIX信號量是一個sem_t類型的變數,但POSIX有兩種信號量的實現機制: 無名信號量 命名信號量 。無名信號量只可以在共享內存的情況下,比如實現進程中各個線程之間的互斥和同步,因此無名信號量也被稱作基於內存的信號量;命名信號量通常用於不共享內存的情況下,比如進程間通信。

同時,在創建信號量時,根據信號量取值的不同,POSIX信號量還可以分為:

下面是POSIX信號量函數介面:

信號量的函數都以sem_開頭,線程中使用的基本信號函數有4個,他們都聲明在頭文件semaphore.h中,該頭文件定義了用於信號量操作的sem_t類型:

【sem_init函數】:

該函數用於創建信號量,原型如下:

該函數初始化由sem指向的信號對象,設置它的共享選項,並給它一個初始的整數值。pshared控制信號量的類型,如果其值為0,就表示信號量是當前進程的局部信號量,否則信號量就可以在多個進程間共享,value為sem的初始值。

該函數調用成功返回0,失敗返回-1。

【sem_destroy函數】:

該函數用於對用完的信號量進行清理,其原型如下:

成功返回0,失敗返回-1。

【sem_wait函數】:

該函數用於以原子操作的方式將信號量的值減1。原子操作就是,如果兩個線程企圖同時給一個信號量加1或減1,它們之間不會互相干擾。其原型如下:

sem指向的對象是sem_init調用初始化的信號量。調用成功返回0,失敗返回-1。

sem_trywait()則是sem_wait()的非阻塞版本,當條件不滿足時(信號量為0時),該函數直接返回EAGAIN錯誤而不會阻塞等待。

sem_timedwait()功能與sem_wait()類似,只是在指定的abs_timeout時間內等待,超過時間則直接返回ETIMEDOUT錯誤。

【sem_post函數】:

該函數用於以原子操作的方式將信號量的值加1,其原型如下:

與sem_wait一樣,sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1。

【sem_getvalue函數】:

該函數返回當前信號量的值,通過restrict輸出參數返回。如果當前信號量已經上鎖(即同步對象不可用),那麼返回值為0,或為負數,其絕對值就是等待該信號量解鎖的線程數。

【實例1】:

【實例2】:

之所以稱為命名信號量,是因為它有一個名字、一個用戶ID、一個組ID和許可權。這些是提供給不共享內存的那些進程使用命名信號量的介面。命名信號量的名字是一個遵守路徑名構造規則的字元串。

【sem_open函數】:

該函數用於創建或打開一個命名信號量,其原型如下:

參數name是一個標識信號量的字元串。參數oflag用來確定是創建信號量還是連接已有的信號量。

oflag的參數可以為0,O_CREAT或O_EXCL:如果為0,表示打開一個已存在的信號量;如果為O_CREAT,表示如果信號量不存在就創建一個信號量,如果存在則打開被返回,此時mode和value都需要指定;如果為O_CREAT|O_EXCL,表示如果信號量存在則返回錯誤。

mode參數用於創建信號量時指定信號量的許可權位,和open函數一樣,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。

value表示創建信號量時,信號量的初始值。

【sem_close函數】:

該函數用於關閉命名信號量:

單個程序可以用sem_close函數關閉命名信號量,但是這樣做並不能將信號量從系統中刪除,因為命名信號量在單個程序執行之外是具有持久性的。當進程調用_exit、exit、exec或從main返回時,進程打開的命名信號量同樣會被關閉。

【sem_unlink函數】:

sem_unlink函數用於在所有進程關閉了命名信號量之後,將信號量從系統中刪除:

【信號量操作函數】:

與無名信號量一樣,操作信號量的函數如下:

命名信號量是隨內核持續的。當命名信號量創建後,即使當前沒有進程打開某個信號量,它的值依然保持,直到內核重新自舉或調用sem_unlink()刪除該信號量。

無名信號量的持續性要根據信號量在內存中的位置確定:

很多時候信號量、互斥量和條件變數都可以在某種應用中使用,那這三者的差異有哪些呢?下面列出了這三者之間的差異:

F. 使用阿里雲的linux伺服器說信號燈超時時間已到什麼意思

1、首先確認你在linux上是否安裝ftp軟體vsftpd。可以使用find命令查找下。具體linux下vsftpd的安裝和操作可以參考--2、在windows上安裝ftp客戶端軟體flashfxp,就可以進行linux和windows之前的傳輸了。1、使用flashfxp,輸入你登陸linux的用戶名和密碼。連接類型選擇「sftp over ssh」。就可以通過客戶端界面操作系統裡面的文件了。

閱讀全文

與linux信號燈相關的資料

熱點內容
解壓文件蘋果手機rar 瀏覽:145
centos開機命令行模式 瀏覽:695
遍歷所有listpython 瀏覽:660
力控加密文件夾 瀏覽:515
如何更改移動伺服器密碼 瀏覽:686
蘋果8p手機加密 瀏覽:749
ipad建文件夾怎麼弄 瀏覽:833
iphone13對wap3加密 瀏覽:555
pdf文件打開失敗 瀏覽:913
dubbo怎麼調用不同伺服器介面 瀏覽:40
全能解壓王app歷史版本 瀏覽:75
優先隊列與拓撲排序演算法 瀏覽:281
pdf轉換formacbook 瀏覽:871
pdf文件內容怎麼編輯 瀏覽:48
134壓縮機排氣溫度多少 瀏覽:256
unity等待編譯後 瀏覽:806
黑鯊手機鎖屏視頻在哪個文件夾 瀏覽:781
wow地圖解壓後怎麼壓縮 瀏覽:823
有pdf卻打不開 瀏覽:462
七星彩軟體app怎麼下載 瀏覽:219