在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。
也許有的朋友會說,不光資料需要保護,**也需要保護。提出這個觀點的朋友只看到了資料訪問互斥的表象。在程式的執行空間裡面,什麼最重要的呢?**嗎?當然不是。**只是為了資料的訪問存在的。資料才是我們一切工作的出發點和落腳點。
那麼,有什麼辦法可以保證在某一時刻只有乙個執行緒對資料進行操作呢?四個基本方法:
(1)關中斷
(2)數學互斥方法
(3)作業系統提供的互斥方法
(4)cpu原子操作
為了讓大家可以對這四種方法有詳細的認識,我們可以進行詳細的介紹。
(1)關中斷
要讓資料在某一時刻只被乙個執行緒訪問,方法之一就是停止執行緒排程就可以了。那麼怎樣停止執行緒排程呢?那麼關掉時鐘中斷就可以了啊。在x86裡面的確存在這樣的兩個指令,
view plain
#include
intmain()
return
1;
}
其中cli是關中斷,sti是開中斷。這段**沒有什麼問題,可以編過,當然也可以生成執行檔案。但是在執行的時候會出現乙個異常告警:unhandled exception in test.exe: 0xc0000096: privileged instruction。告警已經說的很清楚了,這是乙個特權指令。只有系統或者核心本身才可以使用這個指令。
不過,大家也可以想象一下。因為平常我們編寫的程式都是應用級別的程式,要是每個程式都是用這些**,那不亂了套了。比如說,你不小心安裝乙個低質量的軟體,說不定什麼時候把你的中斷關了,這樣你的網路就斷了,你的輸入就沒有回應了,你的**什麼都沒有了,這樣的環境你受的了嗎?應用層的軟體是千差萬別的,軟體的水平也是參差不齊的,所以系統不可能相信任何乙個私有軟體,它相信的只是它自己。
(2)數學方法
假設有兩個執行緒(a、b)正要對乙個共享資料進行訪問,那麼怎麼做到他們之間的互斥的呢?其實我們可以這麼做,
view plain
unsigned
intflag[2] = ;
unsigned int
turn = 0;
void
process(unsigned
intindex)
其實,學過作業系統的朋友都知道,上面的演算法其實就是peterson演算法,可惜它只能用於兩個執行緒的資料互斥。當然,這個演算法還可以推廣到更多執行緒之間的互斥,那就是bakery演算法。但是數學演算法有兩個缺點:
a)占有空間多,兩個執行緒就要flag佔兩個單位空間,那麼n個執行緒就要n個flag空間,
b)**編寫複雜,考慮的情況比較複雜
(3)系統提供的互斥演算法
系統提供的互斥演算法其實是我們平時開發中用的最多的互斥工具。就拿windows來說,關於互斥的工具就有臨界區、互斥量、訊號量等等。這類演算法有乙個特點,那就是都是依據系統提高的互斥資源,那麼系統又是怎麼完成這些功能的呢?其實也不難。
系統加鎖過程,
view plain
void
lock(
handle
hlock)
; while
(1);
return
; }
__asm;
schedule();
__asm;
} }
系統解鎖過程,
view plain
void
unlock(
handle
hlock)
; /* 設定標誌, 當前鎖可用 */
__asm;
}
上面其實討論的就是一種最簡單的系統鎖情況。中間沒有涉及到就緒執行緒的壓入和彈出過程,沒有涉及到資源個數的問題,所以不是很複雜。朋友們仔細看看,應該都可以明白**表達的是什麼意思。
(4)cpu的原子操作
因為在多執行緒操作當中,有很大一部分是比較、自增、自減等簡單操作。因為需要互斥的**很少,所以使用互斥量、訊號量並不合算。因此,cpu廠商為了開發的方便,把一些常用的指令設計成了原子指令,在windows上面也被稱為原子鎖,常用的原子操作函式有
view plain
interlockedadd
interlockedexchange
interlockedcompareexchange
interlockedincrement
interlockeddecrement
interlockedand
interlockedor
多執行緒的那點事兒(之資料互斥)
在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。也許有的朋友會說,不...
多執行緒的那點事兒(之資料互斥)
在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。也許有的朋友會說,不...
多執行緒的那點事兒(之資料互斥)
在多執行緒存在的環境中,除了堆疊中的臨時資料之外,所有的資料都是共享的。如果我們需要執行緒之間正確地執行,那麼務必需要保證公共資料的執行和計算是正確的。簡單一點說,就是保證資料在執行的時候必須是互斥的。否則,如果兩個或者多個執行緒在同一時刻對資料進行了操作,那麼後果是不可想象的。也許有的朋友會說,不...