i.MX6ULL終結者Linux併發與競爭原子操作

一隻流浪小法師發表於2020-12-07

1 什麼是原子操作

原子操作,顧名思義,就是說像原子一樣不可再細分不可被中途打斷。一個操作是原子操作,意思就是說這個操作是以原子的方式被執行,要一口氣執行完,執行過程不能夠被系統的其他行為打斷,是一個整體的過程,在其執行過程中,系統的其它行為是插不進來的。
我們現在假設有兩個執行單元A和B,這兩個執行單元要對共享變數X加1,X的初始值是1。當CPU實現加一的操作時,先從記憶體讀取X的值,執行加一的操作,在將X的值寫回記憶體。假如這兩個執行單元A和B是順序執行的,執行過程如圖 1.1:
在這裡插入圖片描述

圖 1.1

按照上圖所示的流程,X變數的值最終變為3,經過了兩次加一操作。但是實際的執行流程可能如圖 1.2所示:
在這裡插入圖片描述

圖 1.2

按照上述流程執行的最終結果X的值為2,這就是一個最簡單的設定變數值的併發與競爭的例子,要解決這個問題就要保證X變數加一操作的三個步驟要作為一個整體執行,也就是作為一個原子存在。
在linux中提供了兩種形式的原子操作,一種是對整數進行的操作,一種是對單獨的位進行操作,並且Linux核心提供了這兩種形式原子操作的API函式,接下來分別看一下這些函式。

2 整型原子操作

在Linux中有一個專門的atomic_t的結構體來完成整型資料的原子操作,此結構體定義在 include/linux/types.h 檔案中,定義如下:

 typedef struct { 
 		int counter; 
 } atomic_t; 

在使用原子操作函式之前,首先要定義一個atomic_t 的變數,如下所示:
atomic_t a; //定義 a
也可以在定義原子變數的時候給原子變數賦初值,如下所示:
atomic_t b = ATOMIC_INIT(0); //定義原子變數 b 並賦初值為 0
可以通過巨集 ATOMIC_INIT 向原子變數賦初值。
原子變數有了,接下來就是對原子變數進行操作,比如讀、寫、增加、減少等等,Linux 核心提供的原子操作 API 函式如下所示:
在這裡插入圖片描述

原子變數和相應的 API 函式使用起來很簡單,參考如下示例:

atomic_t v = ATOMIC_INIT(0); /* 定義並初始化原子變零 v=0 */ 
atomic_set(10); 		/* 設定 v=10 */ 
atomic_read(&v); 		/* 讀取 v 的值,肯定是 10 */ 
atomic_inc(&v); 		/* v 的值加 1,v=11 */

3 位原子操作

位操作也是很常用的操作,Linux 核心也提供了一系列的原子位操作 API 函式,只不過原子位操作不像原子整型變數那樣有個 atomic_t 的資料結構,原子位操作是直接對記憶體進行操作,API 函式如下所示:
函式 作用
在這裡插入圖片描述在這裡插入圖片描述

相關文章