#同步是進程之間,以及進程與系統資源之間的互動。由於 Linux 核心採用多任務,因此在多個進程之間必須有同步機制來確保協調。
Linux 核心中有許多種同步機制。今天我們將重點介紹 kernel 中的非同步和同步機制,其中著重介紹 kernel 中的非同步機制。 kernel 中的非同步機制分為兩種:一種是應用層的同步機制,即應用層執行緒之間的通訊;另一種是核心的同步機制。
當一個執行緒進入內核狀態後,它可以直接與核心溝通。 kernel 中有兩個執行緒是這樣的:一個是執行緒 A,它進入內核態後會直接與核心溝通,告訴它要做什麼,完成後會通知核心。 (我們稱這個操作為 semi)當一個執行緒進入內核態後,它會先與內核溝通一次,然後就可以直接執行了。
kernel 中的同步機製本質上是執行緒間的通訊機制,它們之間透過同步機制來實現通訊。
為了確保系統的正確性和一致性, Linux核心會在進程間通訊的過程中使用阻塞佇列來處理進程間的通訊。阻塞佇列是指在訊息佇列中的某個元素在訊息發出時就被創建,但並不是所有的訊息都會被傳送出去,只有當某一訊息的等待佇列滿了才會被傳送出去。如果接收方等待佇列中沒有訊息,則會接收到通知,如果接收方等待佇列中有訊息,則不會收到通知。
在核心中,對阻塞佇列進行了抽象,即當某個進程發出了一個訊息後,它就被阻塞了。因此,阻塞隊列實際上是一種同步機制。阻塞隊列透過一個特定的函數來建立一個新的對象,該對象包含一個等待隊列指標(Push/Pop)。當等待佇列滿了之後,系統將把該等待佇列指標指向的物件作為第一個發出通知的程序的執行緒。也就是說,該行程會收到通知後才能繼續執行它的任務。
#信號量可以用來發送或接收訊息。當一個行程擁有了一個信號量,就表示他已經擁有了一個屬於自己的信號量,這個信號量是他自己的一個私有變數。這個私有變數是不能被其它進程拿到的。信號量用來表示一個進程所擁有的信號量數量,當這個進程擁有了這個信號量之後,就可以向其它進程發送訊息。這個私有變數只允許這個行程自己使用,不可以把它拿到其它所處理的進程中去。
當一個執行緒擁有了自己的信號量之後,就可以透過共享變數來與其它執行緒進行通訊了。共享變數也是在其它線程中進行使用的,其它線程使用共享變數來和自己進行通訊。
#互斥量主要是針對系統資源來說的。 Linux核心中的互斥又可以分為兩種:共享資源和全域互斥資源。
共享資源就是行程之間共享的,例如一個行程有多個線程,那麼每個執行緒都可以存取這個共享的記憶體空間。全域互斥資源就是行程和執行緒之間只能存取到自己所在的全域記憶體空間。在一個系統中,可以使用互斥來實現多個進程同時在記憶體中執行。但是如果要實現多個進程同時執行,就需要使用同步機制,這樣才能確保所有的進程都能夠在同一個記憶體中運作。使用互斥量,一個行程只能存取到自己所在的全域記憶體空間,而無法存取其它記憶體空間。但是互斥量有一個很大的好處,那就是不會出現進程阻塞等情況。
#訊息佇列的出現,對進程間通訊進行了很大的擴展。在 kernel中,除了同步機制外,還有另一個非同步機制,那就是訊息佇列。我們都知道, Linux核心是支援訊息佇列的。雖然在核心中也有關於訊息隊列的詳細信息,但是由於核心是不支援用戶態的訊息隊列的,所以我們還是要從應用層入手來了解一下訊息隊列。
首先我們先了解訊息佇列是什麼?
訊息佇列是一種特殊的佇列,它能夠滿足多個應用執行緒之間的同步需求。訊息佇列用於提供應用程式與其他進程或執行緒之間的非同步通訊。如果我們需要進行非同步通信,那麼就可以透過使用訊息佇列來進行。例如當我們呼叫 clear ()函數時,我們就可以直接使用一個已註冊的訊息佇列。
那麼要如何建立一個訊息隊列呢?當我們使用ext2. json時,可以在 JAR. json. clear ()中使用 semaphore命令建立一個訊息佇列。
#在共享記憶體中,我們使用的是共享鎖,但因為共享鎖是與某個進程共享內存,所以當你想要獲取共享鎖的時候,你需要向其他進程請求。
就像在上面的例子中,我們透過 volatile關鍵字來存取共享記憶體。此時你並沒有向其他進程請求,所以當你想要取得這個共享鎖時,只需要向其他進程請求。這樣就避免了兩個行程之間的互相競爭,同時也能實現資料的同步。
由於共享鎖是與某個進程共享內存,所以你必須向該進程請求訪問它的位址。對於這種情況來說,最簡單的解決方案就是使用執行緒池。
在執行緒池中有一個叫做「byte」的對象,它也是一個共享鎖。當你想要取得這個鎖時,只需要向 byte物件發送請求就可以了。這時候 byte物件會將你的請求傳送到該執行緒的佇列中,當該執行緒收到請求時,它就會給你回傳一個回應訊息。
#執行緒池是一個非常好的執行緒管理工具,它可以讓多個執行緒同時運行,還可以減少執行緒之間的死鎖和衝突。它還有一個最重要的特點是,可以有效地利用系統的內存,達到提高效率的目的。
執行緒池的使用非常簡單,就是把要執行的任務分配到對應的執行緒池中。當要執行的任務被分配到對應執行緒池後,就可以執行了。使用線程池會為我們帶來很多好處:
#上面介紹了兩種同步機制,那我們來看看內核態的同步機制,在內核態有四種同步方式:
透過上面的分析我們了解到,同步是一個複雜的問題,在內核態是如何完成同步的呢?
首先,在核心態有三個行程:這三個行程都可以互相存取對方的資源,也可以在資源被其他行程請求時進行同步。
當某個行程被阻塞時,它的所有子程序會從等待佇列中取出一個子程序(或者其它子程序),並把它加到阻塞佇列中。當所有子進程都被阻塞時,阻塞佇列中就沒有子進程了。這時,等待佇列中的其他子程序就會把目前執行緒加到等待佇列中。這三個進程在等待過程中不會互相影響,三個線程可以透過設定自己的優先權和其他執行緒來同步。
以上是身為嵌入式開發工程師,關於Linux kernel同步機制你不得不知道的詳細內容。更多資訊請關注PHP中文網其他相關文章!