一些概念:
* 競爭條件: 多個程序併發訪問和操作公共變數,並且執行結果和訪問資料有關的情況。
* 臨界區:這個區間程序的**會改變公共變數.臨界區有乙個特徵:乙個時間只有乙個程序可以進入臨界區,進而不會導致公共變數混亂。進入臨界區的程序必須要先請求進入臨界區以便協調。
* 實現請求進入臨界區的**段稱為進入區。
處理臨界區問題,演算法一定要滿足三個條件:互斥(只有乙個程序可以進入臨界區)、前進(多個請求進入臨界區的程序一定有乙個可以進入臨界區,並且這個決策不能無線推遲)、有限等待(當乙個程序請求進入臨界區,直到這個請求被允許,其他程序進入臨界區的次數有上限)
作業系統的編寫,需要處理核心的臨界區問題,對於這個問題,非搶占核心不存在競爭條件,所以沒有臨界區問題,而搶占核心存在臨界區問題,而且在多處理器問題更甚。
peterson演算法:基於軟體的經典的臨界區演算法
//假設有兩個程序,這是其中之一,另乙個將i與j更換位置即可
dowhile(true);
基於硬體的鎖
如果硬體提供原子性的檢測臨界區條件並且進入臨界區的操作,那麼**可以簡單地使用基於硬體的命令
基於軟體的訊號量
訊號量是乙個整數,除了初始化之外,還有wait和signal兩個原子性的函式可以操作這個整數,wait的用途是將訊號量(整數)自減,如果訊號量不大於0,則等待(迴圈忙等),signal用途是將訊號量自增。將訊號量作為系統的某一種資源,使用wait和signal操作,即可實現申請該資源,如果資源富裕則使用,空缺則等待,使用完則歸還資源的目的。
演示**如下
//可能的wait和signal函式的實現
void wait(int s)//需要注意,這個函式中 操作都需要是原子性的
void signal(int s)
//訊號量使用例項
dowhile(true);
另外,訊號量的兩個操作以前也叫做p、v原語
* 訊號量分為兩種:計數訊號量(訊號量值域不受限,可正可負),二進位制訊號量(訊號量值域只有0、1,也成為互斥鎖)。
* 訊號量的wait函式的設計中,如果訊號量不大於0,則會阻塞在迴圈中忙等,這樣的設計又被成為自旋鎖,自旋鎖有缺點,它浪費了cpu的時間,但也有優點,它避免了上下文的切換。如果上下文切換很耗時,那麼使用自旋鎖是乙個處理的方法,自旋鎖常用於多處理器的場景。
* 乙個克服忙等的方法是,如果wait函式中,發現訊號量不大於0,則讓本程序等待,讓出cpu,知道這個訊號量在其他程序中被執行signal操作,這個時候喚醒等待的訊號量程序。這樣的設計,需要有乙個佇列,儲存等待訊號量的程序pcb,然後在signal函式中檢測,如果訊號量大於0,則喚醒乙個佇列中的程序繼續執行。
說明:有乙個緩衝區(裡面存放若干緩衝項),乙個程序生產資源(生產緩衝項),另乙個程序消費資源(消耗緩衝項),當緩衝項數目有限時,為有限緩衝。這裡需要考慮的是,對於緩衝區的操作應當是互斥操作,生產消耗緩衝項也可以當作乙個計數訊號量處理。所以可以有以下**:
/* 首先定義三個訊號量:mutex、full、empty
* mutex代表進入臨界區的二進位制訊號量,初始化為1
* full代表生產緩衝項的訊號量,初始化為0
* empty代表消耗緩衝項的訊號量,初始化為有限緩衝的上限n
* 這裡的乙個點是,對緩衝項的生產、消費,實現是操作了兩個實際不相關的訊號量(程式不出錯的情況下二者有full+empty=n的關係)
*///生產者**
dowhile(true);
//消費者**
dowhile(true);
說明:在公用乙個資源,比如資料庫、檔案、資料的時候,檢視讀取並不會影響其他的程序,修改會影響其他的程序,所以提出了讀者和寫者的區別,一般而言,要允許多個讀者同時讀,但同一時間只有乙個寫者可以寫。
讀者寫者問題有諸多變種,都與優先順序有關,比如第一讀者寫者問題(讀者優先,新的讀者不會因為有寫者的等待請求而不使用公用資源,也就是說寫者可能一直等不到資源),第二讀者寫者問題(寫者優先,如果有寫者等待,那麼新的讀者只會等待寫者操作資源完成後再讀)
下面是乙個讀者優先的讀者寫者問題的解決示例:
/* 首先定義兩個訊號量:mutex和wrt,以及乙個int型變數readcount
* mutex代表更新readcounter的互斥訊號量,初始化為1
* wrt代表讀和寫的互斥訊號量,初始為1
* readcounter代表讀者的個數,更新它的操作是臨界區操作,需要使用mutex訊號量,初始化為0
*///寫者程序
dowhile(true);
//讀者**
do signal(mutex);
//讀者操作**
wait(mutex);
readcount--;
if(readcount==0)
signal(mutex);
}說明:哲學家進餐說的是一種情況:在圓桌上有5個人,他們用筷子吃飯,但是每乙個人面前只有乙隻筷子,這樣的話,5個人就不能一塊兒吃飯,只能一部分人得到兩隻筷子之後才能吃飯,此外還要保證5個人都有機會得到兩隻筷子,不會一直等待直到餓死或者死鎖。那麼如何管理5個人拿筷子就是乙個問題了。
管程是一種高階的同步構造,訊號量使用不正確會導致不容易發現的錯誤,為了克服訊號量的問題,才提出了這樣的語言構造。
臨界區問題的解決保證了臨界區的執行是原子的,如果兩個臨界區操作併發的執行,其結果是二者按照某一次序順序執行。
資料庫系統很關注原子執行的問題。執行單個邏輯功能的一系列指令或者操作成為事務,事務的執行要求保持原子性,一起成功或者一起失敗。為了保證這一點,引入了提交(執行成功的事務)和撤銷(執行失敗的事務)。撤銷的事務需要回滾,如何回滾,回滾到什麼時候呢?一種方法是使用基於日誌的恢復。
在每一次操作之前,首先要記錄日誌,記錄下事務的所有操作和新值舊值。如果事務執行失敗,則從日誌中查詢出沒有標記結束的日誌,恢復到舊值(undo操作),或者重新執行,更新資料到新值(redo操作),至於到底是哪乙個操作,需要看事務失敗的型別。
因為檢測日誌耗時耗力,因此引入了檢查點,失敗的事務只需要從最近時間的檢查點開始恢復就行。
若干個原子操作併發的執行,其結果是順序執行,稱為序列化。然而,並不是非序列化的操作一定產生錯誤,只有特定持續的執行序列才會導致併發操作產生錯誤,這裡產生錯誤的操作序列成為衝突操作(如果兩個事務共同訪問乙個資料項並且至少有乙個write操作,則兩個事務有衝突操作)。衝突操作的解決需要衝突可序列化,即如果兩個事務的順序執行可以通過一系列非衝突操作的交換得到另乙個執行順序,那麼這個另乙個順序稱為衝突可序列化,這樣的執行序列不會產生錯誤。
為了確保序列化能力,需要一些方法,這裡提出兩種協議:兩段加鎖協議(增長階段只能獲得鎖,收縮階段只能釋放鎖,這種協議可確保衝突序列化,但是不能避免死鎖),基於時間戳的協議(這種協議避免了死鎖,且確保了可序列化)。
LAMP第四部分mysql操作
1.忘記root密碼 編輯mysql主配置檔案 my.cnf 在 mysqld 欄位下新增引數 skip grant 重啟資料庫服務,這樣就可以進入資料庫不用授權了 mysql uroot 修改相應使用者密碼 use mysql update user set password password y...
第四部分 方法3
對employee.calculatepay方法的呼叫是問題的原因。我們需要的是晚繫結。晚繫結 latebinging 意味著編譯器到執行時才選擇要執行的方法。為了迫使編譯器呼叫向上型別轉換得到的物件的方法的正確版本。我們使用了兩個關鍵字 virtual 和override.必須在基類方法中使用vi...
第四部分 方法5
linux繼承了unix作業系統結構清晰的特點。在linux下的檔案結構非常有條理。但是,上述的優點只有在對linux相當熟悉時,才能體會到。vmlinuz 我們已經知道,每乙個linux都有乙個核心 vmlinuz 我們在這個核心上新增上可以完成各種特定功能的模組,每個模組就體現在 linux中各...