critical section 的情景如下富雅。多個(gè)程序會對共享的變量進(jìn)行操作由于對于變量的操作不是原子性的(不可分割,不能被中斷)就會造成數(shù)據(jù)的不一致肛搬。舉個(gè)例子没佑,例如你的銀行卡上有 100 塊錢,如果你同時(shí)在商家 A 與商家 B 同時(shí)消費(fèi) 100 元的東西温赔。如果記賬的過程不是原子性的蛤奢。商家需要先發(fā)請求到銀行用戶在這里想要消費(fèi)100元,銀行后臺程序需要看看用戶的賬戶里面是否錢是充足的,如果錢是充足的就批準(zhǔn)商家的消費(fèi)請求啤贩。由于計(jì)算機(jī)體系結(jié)構(gòu)的原因待秃,memory hierarchy,與操作系統(tǒng)的分時(shí)處理痹屹,如果沒有一定的同步措施章郁,數(shù)據(jù)不一致的情況。在加上現(xiàn)代的程序架構(gòu)會使用多線程志衍,多進(jìn)程的方式解決問題暖庄。會出現(xiàn)這樣的情況,商家 A B 同時(shí)發(fā)出請求楼肪,兩個(gè)子程序同時(shí)從數(shù)據(jù)庫中讀取到用戶賬號里面有 100 元培廓,因此同時(shí)批準(zhǔn)了這兩筆消費(fèi)〈航校總計(jì)消費(fèi)了 200 元肩钠,實(shí)時(shí)上用戶賬號只有 100 元,這時(shí)就會出現(xiàn)沖突象缀。
在單核的情況下蔬将,由于多線程多進(jìn)程是共享cpu計(jì)算時(shí)間爷速,程序 a 讀到賬號上有 100 元錢央星, 還沒進(jìn)行處理,操作系統(tǒng)讓 cpu 執(zhí)行 b惫东,b 也讀到用戶有 100 元莉给。此時(shí)操作系統(tǒng)讓 a 程序繼續(xù)執(zhí)行,并且扣除了用戶賬號上面的余額廉沮,之后操作系統(tǒng)讓程序b繼續(xù)執(zhí)行颓遏,由于此時(shí)程序b不會再去讀取用戶的賬戶所以這個(gè)程序也會批準(zhǔn)這個(gè)交易進(jìn)行。這樣用戶就會平白無故的賺了100元滞时。
如果是在多核或者是多服務(wù)器的情況下叁幢,由于 a,b程序可能會同時(shí)執(zhí)行曼玩,他們同時(shí)讀取到用戶的賬號上面有 100 元,并且同時(shí)批準(zhǔn)了交易篙梢。造成沖突的原因與單核情況下不太一致顷帖。
如果站在更高角度上看是由于不同程序間的數(shù)據(jù)同步問題造成的這一系列沖突榴嗅,不同程序修改的變量無法同步到不同的程序中。如果站在底層看就是由于 memory hierarchy 造成同一個(gè)數(shù)據(jù)會被放在不同地方论咏。盡管有緩存一致性協(xié)議厅贪,但是由于操作不是原子性的所以不同的程序不知道對方程序再干嘛所以會造成沖突。
這就是 critical section 的場景贯吓。
那么如何解決這樣的問題呢?一種方法是通過一定的機(jī)制使得在同一時(shí)間只有一個(gè)程序能夠?qū)τ脩舻馁~號進(jìn)程操作爬舰。Peterson's Solution 算法 就是一種在 單核并發(fā)
的解決方案。注意這里是單核垃你。
bool flag[2];
int turn;
// i process
do{
flag[i] = true;
turn = j;
while(flag[j] && turn == j); // do nothing
//critical section
flag[i] = false;
}
// j process
do{
flag[j] = true;
turn = i;
while(flag[i] && turn == i); // do nothing
//critical section
flag[j] = false;
}
fage[i] == true
時(shí),表示 程序 i 準(zhǔn)備進(jìn)入 critical section了官还,而 turn 則表示某個(gè)程序正在 critical section林说。那這個(gè)算法如何保證同時(shí)只有一個(gè)程序在critical section里面呢?這里有一個(gè)前提假設(shè)就是 load and write 是原子性的珠移。所以同一時(shí)刻,turn 要么是 i 要么是 j浓瞪。所以 如果兩個(gè)程序都是 ready 的,但是只有一個(gè)程序能夠進(jìn)入 critical section英岭,另一個(gè)程序會一直循環(huán)等待。在這里的 turn 變量的唯一性(不同程序讀到的都是一樣的)很重要荧库。
但是如果換到多核情況就會出現(xiàn)场刑, i 和 j 同時(shí)讀到 turn == i
turn == j
。此算法就會失效瞎疼。