多執行緒的那點事兒(之資料互斥)

2021-07-23 02:39:22 字數 3015 閱讀 8408

在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。

也許有的朋友會說,不光資料需要保護,**也需要保護。提出這個觀點的朋友只看到了資料訪問互斥的表象。在程式的執行空間裡面,什麼最重要的呢?**嗎?當然不是。**只是為了資料的訪問存在的。資料才是我們一切工作的出發點和落腳點。

那麼,有什麼辦法可以保證在某一時刻只有乙個執行緒對資料進行操作呢?四個基本方法:

(1)關中斷

(2)數學互斥方法

(3)作業系統提供的互斥方法

(4)cpu原子操作

為了讓大家可以對這四種方法有詳細的認識,我們可以進行詳細的介紹。

(1)關中斷

要讓資料在某一時刻只被乙個執行緒訪問,方法之一就是停止執行緒排程就可以了。那麼怎樣停止執行緒排程呢?那麼關掉時鐘中斷就可以了啊。在x86裡面的確存在這樣的兩個指令,

[cpp]view plain

copy

print

?#include 

int main()  

return 1;  

}  

#include int main()

return 1;

}

其中cli是關中斷,sti是開中斷。這段**沒有什麼問題,可以編過,當然也可以生成執行檔案。但是在執行的時候會出現乙個異常告警:unhandled exception in test.exe: 0xc0000096:  privileged instruction。告警已經說的很清楚了,這是乙個特權指令。只有系統或者核心本身才可以使用這個指令。

不過,大家也可以想象一下。因為平常我們編寫的程式都是應用級別的程式,要是每個程式都是用這些**,那不亂了套了。比如說,你不小心安裝乙個低質量的軟體,說不定什麼時候把你的中斷關了,這樣你的網路就斷了,你的輸入就沒有回應了,你的**什麼都沒有了,這樣的環境你受的了嗎?應用層的軟體是千差萬別的,軟體的水平也是參差不齊的,所以系統不可能相信任何乙個私有軟體,它相信的只是它自己。

(2)數學方法

假設有兩個執行緒(a、b)正要對乙個共享資料進行訪問,那麼怎麼做到他們之間的互斥的呢?其實我們可以這麼做,

[cpp]view plain

copy

print

?unsigned int flag[2] = ;  

unsigned int turn = 0;  

void process(unsigned int index)    

unsigned int flag[2] = ;

unsigned int turn = 0;

void process(unsigned int index)

其實,學過作業系統的朋友都知道,上面的演算法其實就是peterson演算法,可惜它只能用於兩個執行緒的資料互斥。當然,這個演算法還可以推廣到更多執行緒之間的互斥,那就是bakery演算法。但是數學演算法有兩個缺點:

a)占有空間多,兩個執行緒就要flag佔兩個單位空間,那麼n個執行緒就要n個flag空間,

b)**編寫複雜,考慮的情況比較複雜

(3)系統提供的互斥演算法

系統提供的互斥演算法其實是我們平時開發中用的最多的互斥工具。就拿windows來說,關於互斥的工具就有臨界區、互斥量、訊號量等等。這類演算法有乙個特點,那就是都是依據系統提高的互斥資源,那麼系統又是怎麼完成這些功能的呢?其實也不難。

系統加鎖過程,

[cpp]view plain

copy

print

?void lock(handle hlock)  

;  while(1);  

return;  

}  __asm;  

schedule();  

__asm;  

}  }  

void lock(handle hlock)

; while(1);

return;

} __asm;

schedule();

__asm;

}}

系統解鎖過程,

[cpp]view plain

copy

print

?void unlock(handle hlock)  

;  /* 設定標誌, 當前鎖可用 */

__asm;  

}  

void unlock(handle hlock)

; /* 設定標誌, 當前鎖可用 */

__asm;

}

上面其實討論的就是一種最簡單的系統鎖情況。中間沒有涉及到就緒執行緒的壓入和彈出過程,沒有涉及到資源個數的問題,所以不是很複雜。朋友們仔細看看,應該都可以明白**表達的是什麼意思。

(4)cpu的原子操作

因為在多執行緒操作當中,有很大一部分是比較、自增、自減等簡單操作。因為需要互斥的**很少,所以使用互斥量、訊號量並不合算。因此,cpu廠商為了開發的方便,把一些常用的指令設計成了原子指令,在windows上面也被稱為原子鎖,常用的原子操作函式有

[cpp]view plain

copy

print

?interlockedadd  

interlockedexchange  

interlockedcompareexchange  

interlockedincrement  

interlockeddecrement  

interlockedand  

interlockedor  

多執行緒那點事兒(之資料互斥)

在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。也許有的朋友會說,不...

多執行緒的那點事兒(之資料互斥)

在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。也許有的朋友會說,不...

多執行緒的那點事兒(之資料互斥)

在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。也許有的朋友會說,不...