當前位置:首頁 » 文件傳輸 » 如何並發的訪問臨界區
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

如何並發的訪問臨界區

發布時間: 2022-04-15 01:44:21

Ⅰ 對臨界區管理的基本原則是什麼

臨界區,每個進程中訪問臨界資源的那段程序叫做臨界區,是一個訪問共享資源的程序片段。進程對臨界區的訪問必須互斥,每次只允許一個進程進去臨界區,其他進程等待。
臨界資源:指每次只允許一個進程訪問的資源,分硬體臨界資源、軟體臨界資源。
臨界區管理的基本原則是:
①如果有若干進程要求進入空閑的臨界區,一次僅允許一個進程進入。②任何時候,處於臨界區內的進程不可多於一個。如已有進程進入自己的臨界區,則其它所有試圖進入臨界區的進程必須等待。③進入臨界區的進程要在有限時間內退出,以便其它進程能及時進入自己的臨界區。④如果進程不能進入自己的臨界區,則應讓出CPU,避免進程出現「忙等」現象。
1.臨界資源
臨界資源是一次僅允許一個進程使用的共享資源。各進程採取互斥的方式,實現共享的資源稱作臨界資源。屬於臨界資源的硬體有,列印機,磁帶機等;軟體有消息隊列,變數,數組,緩沖區等。諸進程間採取互斥方式,實現對這種資源的共享。
2.臨界區:
每個進程中訪問臨界資源的那段代碼稱為臨界區,每次只允許一個進程進入臨界區,進入後,不允許其他進程進入。不論是硬體臨界資源還是軟體臨界資源,多個進程必須互斥的對它進行訪問。多個進程涉及到同一個臨界資源的的臨界區稱為相關臨界區。使用臨界區時,一般不允許其運行時間過長,只要運行在臨界區的線程還沒有離開,其他所有進入此臨界區的線程都會被掛起而進入等待狀態,並在一定程度上影響程序的運行性能。

Ⅱ 臨界區是指並發進程中訪問共享變數的什麼段

臨界區是指並發進程中訪問共享變數的程序段

Ⅲ 請用技術語言介紹下線程同步,並發操作怎麼控制

現在流行的進程線程同步互斥的控制機制,其實是由最原始最基本的4種方法實現的。由這4種方法組合優化就有了.Net和Java下靈活多變的,編程簡便的線程進程式控制制手段。

這4種方法具體定義如下 在《操作系統教程》ISBN 7-5053-6193-7 一書中可以找到更加詳細的解釋

1、臨界區:通過對多線程的串列化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。

2、互斥量:為協調共同對一個共享資源的單獨訪問而設計的。

3、信號量:為控制一個具有有限數量用戶資源而設計。

4、事 件:用來通知線程有一些事件已發生,從而啟動後繼任務的開始。

臨界區(Critical Section)

保證在某一時刻只有一個線程能訪問數據的簡便辦法。在任意時刻只允許一個線程對共享資源進行訪問。如果有多個線程試圖同時訪問臨界區,那麼在有一個線程進入後其他所有試圖訪問此臨界區的線程將被掛起,並一直持續到進入臨界區的線程離開。臨界區在被釋放後,其他線程可以繼續搶占,並以此達到用原子方式操作共享資源的目的。

臨界區包含兩個操作原語:

EnterCriticalSection() 進入臨界區
LeaveCriticalSection() 離開臨界區

EnterCriticalSection()語句執行後代碼將進入臨界區以後無論發生什麼,必須確保與之匹配的LeaveCriticalSection()都能夠被執行到。否則臨界區保護的共享資源將永遠不會被釋放。雖然臨界區同步速度很快,但卻只能用來同步本進程內的線程,而不可用來同步多個進程中的線程。

MFC提供了很多功能完備的類,我用MFC實現了臨界區。MFC為臨界區提供有一個CCriticalSection類,使用該類進行線程同步處理是非常簡單的。只需在線程函數中用CCriticalSection類成員函數Lock()和UnLock()標定出被保護代碼片段即可。Lock()後代碼用到的資源自動被視為臨界區內的資源被保護。UnLock後別的線程才能訪問這些資源。

//CriticalSection
CCriticalSection global_CriticalSection;

// 共享資源
char global_Array[256];

//初始化共享資源
void InitializeArray()
{
for(int i = 0;i<256;i++)
{
global_Array[i]=I;
}
}

//寫線程
UINT Global_ThreadWrite(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
//進入臨界區
global_CriticalSection.Lock();
for(int i = 0;i<256;i++)
{
global_Array[i]=W;
ptr->SetWindowText(global_Array);
Sleep(10);
}
//離開臨界區
global_CriticalSection.Unlock();
return 0;
}

//刪除線程
UINT Global_ThreadDelete(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
//進入臨界區
global_CriticalSection.Lock();
for(int i = 0;i<256;i++)
{
global_Array[i]=D;
ptr->SetWindowText(global_Array);
Sleep(10);
}
//離開臨界區
global_CriticalSection.Unlock();
return 0;
}

//創建線程並啟動線程
void CCriticalSectionsDlg::OnBnClickedButtonLock()
{
//Start the first Thread
CWinThread *ptrWrite = AfxBeginThread(Global_ThreadWrite,
&m_Write,
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
ptrWrite->ResumeThread();

//Start the second Thread
CWinThread *ptrDelete = AfxBeginThread(Global_ThreadDelete,
&m_Delete,
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
ptrDelete->ResumeThread();
}

在測試程序中,Lock UnLock兩個按鈕分別實現,在有臨界區保護共享資源的執行狀態,和沒有臨界區保護共享資源的執行狀態。

程序運行結果

互斥量(Mutex)

互斥量跟臨界區很相似,只有擁有互斥對象的線程才具有訪問資源的許可權,由於互斥對象只有一個,因此就決定了任何情況下此共享資源都不會同時被多個線程所訪問。當前占據資源的線程在任務處理完後應將擁有的互斥對象交出,以便其他線程在獲得後得以訪問資源。互斥量比臨界區復雜。因為使用互斥不僅僅能夠在同一應用程序不同線程中實現資源的安全共享,而且可以在不同應用程序的線程之間實現對資源的安全共享。

互斥量包含的幾個操作原語:
CreateMutex() 創建一個互斥量
OpenMutex() 打開一個互斥量
ReleaseMutex() 釋放互斥量
WaitForMultipleObjects() 等待互斥量對象

同樣MFC為互斥量提供有一個CMutex類。使用CMutex類實現互斥量操作非常簡單,但是要特別注意對CMutex的構造函數的調用
CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL)
不用的參數不能亂填,亂填會出現一些意想不到的運行結果。

//創建互斥量
CMutex global_Mutex(0,0,0);

// 共享資源
char global_Array[256];

void InitializeArray()
{
for(int i = 0;i<256;i++)
{
global_Array[i]=I;
}
}
UINT Global_ThreadWrite(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
global_Mutex.Lock();
for(int i = 0;i<256;i++)
{
global_Array[i]=W;
ptr->SetWindowText(global_Array);
Sleep(10);
}
global_Mutex.Unlock();
return 0;
}

UINT Global_ThreadDelete(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
global_Mutex.Lock();
for(int i = 0;i<256;i++)
{
global_Array[i]=D;
ptr->SetWindowText(global_Array);
Sleep(10);
}
global_Mutex.Unlock();
return 0;
}

同樣在測試程序中,Lock UnLock兩個按鈕分別實現,在有互斥量保護共享資源的執行狀態,和沒有互斥量保護共享資源的執行狀態。

程序運行結果

信號量(Semaphores)

信號量對象對線程的同步方式與前面幾種方法不同,信號允許多個線程同時使用共享資源,這與操作系統中的PV操作相同。它指出了同時訪問共享資源的線程最大數目。它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目。在用CreateSemaphore()創建信號量時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設置為最大資源計數,每增加一個線程對共享資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大於0的,就可以發出信號量信號。但是當前可用計數減小到0時則說明當前佔用資源的線程數已經達到了所允許的最大數目,不能在允許其他線程的進入,此時的信號量信號將無法發出。線程在處理完共享資源後,應在離開的同時通過ReleaseSemaphore()函數將當前可用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。

PV操作及信號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。信號量S是一個整數,S大於等於零時代表可供並發進程使用的資源實體數,但S小於零時則表示正在等待使用共享資源的進程數。

P操作 申請資源:

(1)S減1;
(2)若S減1後仍大於等於零,則進程繼續執行;
(3)若S減1後小於零,則該進程被阻塞後進入與該信號相對應的隊列中,然後轉入進程調度。

V操作 釋放資源:

(1)S加1;
(2)若相加結果大於零,則進程繼續執行;
(3)若相加結果小於等於零,則從該信號的等待隊列中喚醒一個等待進程,然後再返回原進程繼續執行或轉入進程調度。

信號量包含的幾個操作原語:

CreateSemaphore() 創建一個信號量
OpenSemaphore() 打開一個信號量
ReleaseSemaphore() 釋放信號量
WaitForSingleObject() 等待信號量

//信號量句柄
HANDLE global_Semephore;

// 共享資源
char global_Array[256];
void InitializeArray()
{
for(int i = 0;i<256;i++)
{
global_Array[i]=I;
}
}
//線程1
UINT Global_ThreadOne(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
//等待對共享資源請求被通過 等於 P操作
WaitForSingleObject(global_Semephore, INFINITE);
for(int i = 0;i<256;i++)
{
global_Array[i]=O;
ptr->SetWindowText(global_Array);
Sleep(10);
}
//釋放共享資源 等於 V操作
ReleaseSemaphore(global_Semephore, 1, NULL);
return 0;
}

UINT Global_ThreadTwo(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
WaitForSingleObject(global_Semephore, INFINITE);
for(int i = 0;i<256;i++)
{
global_Array[i]=T;
ptr->SetWindowText(global_Array);
Sleep(10);
}
ReleaseSemaphore(global_Semephore, 1, NULL);
return 0;
}

UINT Global_ThreadThree(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
WaitForSingleObject(global_Semephore, INFINITE);
for(int i = 0;i<256;i++)
{
global_Array[i]=H;
ptr->SetWindowText(global_Array);
Sleep(10);
}
ReleaseSemaphore(global_Semephore, 1, NULL);
return 0;
}

void CSemaphoreDlg::OnBnClickedButtonOne()
{
//設置信號量 1 個資源 1同時只可以有一個線程訪問
global_Semephore= CreateSemaphore(NULL, 1, 1, NULL);
this->StartThread();
// TODO: Add your control notification handler code here
}

void CSemaphoreDlg::OnBnClickedButtonTwo()
{
//設置信號量 2 個資源 2 同時只可以有兩個線程訪問
global_Semephore= CreateSemaphore(NULL, 2, 2, NULL);
this->StartThread();
// TODO: Add your control notification handler code here
}

void CSemaphoreDlg::OnBnClickedButtonThree()
{
//設置信號量 3 個資源 3 同時只可以有三個線程訪問
global_Semephore= CreateSemaphore(NULL, 3, 3, NULL);
this->StartThread();
// TODO: Add your control notification handler code here
}

信號量的使用特點使其更適用於對Socket(套接字)程序中線程的同步。例如,網路上的HTTP伺服器要對同一時間內訪問同一頁面的用戶數加以限制,這時可以為每一個用戶對伺服器的頁面請求設置一個線程,而頁面則是待保護的共享資源,通過使用信號量對線程的同步作用可以確保在任一時刻無論有多少用戶對某一頁面進行訪問,只有不大於設定的最大用戶數目的線程能夠進行訪問,而其他的訪問企圖則被掛起,只有在有用戶退出對此頁面的訪問後才有可能進入。

程序運行結果

事件(Event)

事件對象也可以通過通知操作的方式來保持線程的同步。並且可以實現不同進程中的線程同步操作。

信號量包含的幾個操作原語:

CreateEvent() 創建一個信號量
OpenEvent() 打開一個事件
SetEvent() 回置事件
WaitForSingleObject() 等待一個事件
WaitForMultipleObjects() 等待多個事件
WaitForMultipleObjects 函數原型:
WaitForMultipleObjects(
IN DWORD nCount, // 等待句柄數
IN CONST HANDLE *lpHandles, //指向句柄數組
IN BOOL bWaitAll, //是否完全等待標志
IN DWORD dwMilliseconds //等待時間


參數nCount指定了要等待的內核對象的數目,存放這些內核對象的數組由lpHandles來指向。fWaitAll對指定的這nCount個內核對象的兩種等待方式進行了指定,為TRUE時當所有對象都被通知時函數才會返回,為FALSE則只要其中任何一個得到通知就可以返回。dwMilliseconds在這里的作用與在WaitForSingleObject()中的作用是完全一致的。如果等待超時,函數將返回WAIT_TIMEOUT。

//事件數組
HANDLE global_Events[2];

// 共享資源
char global_Array[256];

void InitializeArray()
{
for(int i = 0;i<256;i++)
{
global_Ar
ray[i]=I;
}
}

UINT Global_ThreadOne(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
for(int i = 0;i<256;i++)
{
global_Array[i]=O;
ptr->SetWindowText(global_Array);
Sleep(10);
}
//回置事件
SetEvent(global_Events[0]);
return 0;
}

UINT Global_ThreadTwo(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
for(int i = 0;i<256;i++)
{
global_Array[i]=T;
ptr->SetWindowText(global_Array);
Sleep(10);
}
//回置事件
SetEvent(global_Events[1]);
return 0;
}

UINT Global_ThreadThree(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam;
ptr->SetWindowText("");
//等待兩個事件都被回置
WaitForMultipleObjects(2, global_Events, true, INFINITE);
for(int i = 0;i<256;i++)
{
global_Array[i]=H;
ptr->SetWindowText(global_Array);
Sleep(10);
}
return 0;
}
void CEventDlg::OnBnClickedButtonStart()
{
for (int i = 0; i < 2; i++)
{
//實例化事件
global_Events[i]=CreateEvent(NULL,false,false,NULL);
}
CWinThread *ptrOne = AfxBeginThread(Global_ThreadOne,
&m_One,
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
ptrOne->ResumeThread();

//Start the second Thread
CWinThread *ptrTwo = AfxBeginThread(Global_ThreadTwo,
&m_Two,
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
ptrTwo->ResumeThread();

//Start the Third Thread
CWinThread *ptrThree = AfxBeginThread(Global_ThreadThree,
&m_Three,
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
ptrThree->ResumeThread();
// TODO: Add your control notification handler code here
}

事件可以實現不同進程中的線程同步操作,並且可以方便的實現多個線程的優先比較等待操作,例如寫多個WaitForSingleObject來代替WaitForMultipleObjects從而使編程更加靈活。

程序運行結果

總結:

1. 互斥量與臨界區的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越進程使用。所以創建互斥量需要的資源更多,所以如果只為了在進程內部是用的話使用臨界區會帶來速度上的優勢並能夠減少資源佔用量。因為互斥量是跨進程的互斥量一旦被創建,就可以通過名字打開它。

2. 互斥量(Mutex),信號燈(Semaphore),事件(Event)都可以被跨越進程使用來進行同步數據操作,而其他的對象與數據同步操作無關,但對於進程和線程來講,如果進程和線程在運行狀態則為無信號狀態,在退出後為有信號狀態。所以可以使用WaitForSingleObject來等待進程和線程退出。

3. 通過互斥量可以指定資源被獨占的方式使用,但如果有下面一種情況通過互斥量就無法處理,比如現在一位用戶購買了一份三個並發訪問許可的資料庫系統,可以根據用戶購買的訪問許可數量來決定有多少個線程/進程能同時進行資料庫操作,這時候如果利用互斥量就沒有辦法完成這個要求,信號燈對象可以說是一種資源計數器。

疑問:

在 Linux 上,有兩類信號量。第一類是由 semget/semop/semctl API 定義的信號量的 SVR4(System V Release 4)版本。第二類是由 sem_init/sem_wait/sem_post/interfaces 定義的 POSIX 介面。 它們具有相同的功能,但介面不同。 在2.4.x內核中,信號量數據結構定義為(include/asm/semaphore.h)。

但是在Linux中沒有對互斥量的具體提法,只是看到說互斥量是信號量的一種特殊情況,當信號量的最大資源數=1同時可以訪問共享資源的線程數=1 就是互斥量了。臨界區的定義也比較模糊。沒有找到用事件處理線程/進程同步互斥的操作的相關資料。在Linux下用GCC/G++編譯標准C++代碼,信號量的操作幾乎和Windows下VC7的編程一樣,不用改多少就順利移植了,可是互斥量,事件,臨界區的Linux移植沒有成功。

請採納。

Ⅳ 如何實現linux下多線程之間的互斥與同步

Linux設備驅動中必須解決的一個問題是多個進程對共享資源的並發訪問,並發訪問會導致競態,linux提供了多種解決競態問題的方式,這些方式適合不同的應用場景。

Linux內核是多進程、多線程的操作系統,它提供了相當完整的內核同步方法。內核同步方法列表如下:
中斷屏蔽
原子操作
自旋鎖
讀寫自旋鎖
順序鎖
信號量
讀寫信號量
BKL(大內核鎖)
Seq鎖
一、並發與競態:
定義:
並發(concurrency)指的是多個執行單元同時、並行被執行,而並發的執行單元對共享資源(硬體資源和軟體上的全局變數、靜態變數等)的訪問則很容易導致競態(race conditions)。
在linux中,主要的競態發生在如下幾種情況:
1、對稱多處理器(SMP)多個CPU
特點是多個CPU使用共同的系統匯流排,因此可訪問共同的外設和存儲器。
2、單CPU內進程與搶占它的進程
3、中斷(硬中斷、軟中斷、Tasklet、底半部)與進程之間
只要並發的多個執行單元存在對共享資源的訪問,競態就有可能發生。
如果中斷處理程序訪問進程正在訪問的資源,則競態也會會發生。
多個中斷之間本身也可能引起並發而導致競態(中斷被更高優先順序的中斷打斷)。

解決競態問題的途徑是保證對共享資源的互斥訪問,所謂互斥訪問就是指一個執行單元在訪問共享資源的時候,其他的執行單元都被禁止訪問。

訪問共享資源的代碼區域被稱為臨界區,臨界區需要以某種互斥機制加以保護,中斷屏蔽,原子操作,自旋鎖,和信號量都是linux設備驅動中可採用的互斥途徑。

臨界區和競爭條件:
所謂臨界區(critical regions)就是訪問和操作共享數據的代碼段,為了避免在臨界區中並發訪問,編程者必須保證這些代碼原子地執行——也就是說,代碼在執行結束前不可被打斷,就如同整個臨界區是一個不可分割的指令一樣,如果兩個執行線程有可能處於同一個臨界區中,那麼就是程序包含一個bug,如果這種情況發生了,我們就稱之為競爭條件(race conditions),避免並發和防止競爭條件被稱為同步。

死鎖:
死鎖的產生需要一定條件:要有一個或多個執行線程和一個或多個資源,每個線程都在等待其中的一個資源,但所有的資源都已經被佔用了,所有線程都在相互等待,但它們永遠不會釋放已經佔有的資源,於是任何線程都無法繼續,這便意味著死鎖的發生。

二、中斷屏蔽
在單CPU范圍內避免競態的一種簡單方法是在進入臨界區之前屏蔽系統的中斷。
由於linux內核的進程調度等操作都依賴中斷來實現,內核搶占進程之間的並發也就得以避免了。
中斷屏蔽的使用方法:
local_irq_disable()//屏蔽中斷
//臨界區
local_irq_enable()//開中斷
特點:
由於linux系統的非同步IO,進程調度等很多重要操作都依賴於中斷,在屏蔽中斷期間所有的中斷都無法得到處理,因此長時間的屏蔽是很危險的,有可能造成數據丟失甚至系統崩潰,這就要求在屏蔽中斷之後,當前的內核執行路徑應當盡快地執行完臨界區的代碼。
中斷屏蔽只能禁止本CPU內的中斷,因此,並不能解決多CPU引發的競態,所以單獨使用中斷屏蔽並不是一個值得推薦的避免競態的方法,它一般和自旋鎖配合使用。

三、原子操作
定義:原子操作指的是在執行過程中不會被別的代碼路徑所中斷的操作。
(原子原本指的是不可分割的微粒,所以原子操作也就是不能夠被分割的指令)
(它保證指令以「原子」的方式執行而不能被打斷)
原子操作是不可分割的,在執行完畢不會被任何其它任務或事件中斷。在單處理器系統(UniProcessor)中,能夠在單條指令中完成的操作都可以認為是" 原子操作",因為中斷只能發生於指令之間。這也是某些CPU指令系統中引入了test_and_set、test_and_clear等指令用於臨界資源互斥的原因。但是,在對稱多處理器(Symmetric Multi-Processor)結構中就不同了,由於系統中有多個處理器在獨立地運行,即使能在單條指令中完成的操作也有可能受到干擾。我們以decl (遞減指令)為例,這是一個典型的"讀-改-寫"過程,涉及兩次內存訪問。
通俗理解:
原子操作,顧名思義,就是說像原子一樣不可再細分。一個操作是原子操作,意思就是說這個操作是以原子的方式被執行,要一口氣執行完,執行過程不能夠被OS的其他行為打斷,是一個整體的過程,在其執行過程中,OS的其它行為是插不進來的。
分類:linux內核提供了一系列函數來實現內核中的原子操作,分為整型原子操作和位原子操作,共同點是:在任何情況下操作都是原子的,內核代碼可以安全的調用它們而不被打斷。

原子整數操作:
針對整數的原子操作只能對atomic_t類型的數據進行處理,在這里之所以引入了一個特殊的數據類型,而沒有直接使用C語言的int型,主要是出於兩個原因:
第一、讓原子函數只接受atomic_t類型的操作數,可以確保原子操作只與這種特殊類型數據一起使用,同時,這也確保了該類型的數據不會被傳遞給其它任何非原子函數;
第二、使用atomic_t類型確保編譯器不對相應的值進行訪問優化——這點使得原子操作最終接收到正確的內存地址,而不是一個別名,最後就是在不同體系結構上實現原子操作的時候,使用atomic_t可以屏蔽其間的差異。
原子整數操作最常見的用途就是實現計數器。
另一點需要說明原子操作只能保證操作是原子的,要麼完成,要麼不完成,不會有操作一半的可能,但原子操作並不能保證操作的順序性,即它不能保證兩個操作是按某個順序完成的。如果要保證原子操作的順序性,請使用內存屏障指令。
atomic_t和ATOMIC_INIT(i)定義
typedef struct { volatile int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i) }

在你編寫代碼的時候,能使用原子操作的時候,就盡量不要使用復雜的加鎖機制,對多數體系結構來講,原子操作與更復雜的同步方法相比較,給系統帶來的開銷小,對高速緩存行的影響也小,但是,對於那些有高性能要求的代碼,對多種同步方法進行測試比較,不失為一種明智的作法。

原子位操作:
針對位這一級數據進行操作的函數,是對普通的內存地址進行操作的。它的參數是一個指針和一個位號。

為方便其間,內核還提供了一組與上述操作對應的非原子位函數,非原子位函數與原子位函數的操作完全相同,但是,前者不保證原子性,且其名字前綴多兩個下劃線。例如,與test_bit()對應的非原子形式是_test_bit(),如果你不需要原子性操作(比如,如果你已經用鎖保護了自己的數據),那麼這些非原子的位函數相比原子的位函數可能會執行得更快些。

四、自旋鎖
自旋鎖的引入:
如 果每個臨界區都能像增加變數這樣簡單就好了,可惜現實不是這樣,而是臨界區可以跨越多個函數,例如:先得從一個數據結果中移出數據,對其進行格式轉換和解 析,最後再把它加入到另一個數據結構中,整個執行過程必須是原子的,在數據被更新完畢之前,不能有其他代碼讀取這些數據,顯然,簡單的原子操作是無能為力 的(在單處理器系統(UniProcessor)中,能夠在單條指令中完成的操作都可以認為是" 原子操作",因為中斷只能發生於指令之間),這就需要使用更為復雜的同步方法——鎖來提供保護。

自旋鎖的介紹:
Linux內核中最常見的鎖是自旋鎖(spin lock),自旋鎖最多隻能被一個可執行線程持有,如果一個執行線程試圖獲得一個被爭用(已經被持有)的自旋鎖,那麼該線程就會一直進行忙循環—旋轉—等待鎖重新可用,要是鎖未被爭用,請求鎖的執行線程便能立刻得到它,繼續執行,在任意時間,自旋鎖都可以防止多於一個的執行線程同時進入理解區,注意同一個鎖可以用在多個位置—例如,對於給定數據的所有訪問都可以得到保護和同步。
一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用時自旋(特別浪費處理器時間),所以自旋鎖不應該被長時間持有,事實上,這點正是使用自旋鎖的初衷,在短期間內進行輕量級加鎖,還可以採取另外的方式來處理對鎖的爭用:讓請求線程睡眠,直到鎖重新可用時再喚醒它,這樣處理器就不必循環等待,可以去執行其他代碼,這也會帶來一定的開銷——這里有兩次明顯的上下文切換, 被阻塞的線程要換出和換入。因此,持有自旋鎖的時間最好小於完成兩次上下文切換的耗時,當然我們大多數人不會無聊到去測量上下文切換的耗時,所以我們讓持 有自旋鎖的時間應盡可能的短就可以了,信號量可以提供上述第二種機制,它使得在發生爭用時,等待的線程能投入睡眠,而不是旋轉。
自旋鎖可以使用在中斷處理程序中(此處不能使用信號量,因為它們會導致睡眠),在中斷處理程序中使用自旋鎖時,一定要在獲取鎖之前,首先禁止本地中斷(在 當前處理器上的中斷請求),否則,中斷處理程序就會打斷正持有鎖的內核代碼,有可能會試圖去爭用這個已經持有的自旋鎖,這樣以來,中斷處理程序就會自旋, 等待該鎖重新可用,但是鎖的持有者在這個中斷處理程序執行完畢前不可能運行,這正是我們在前一章節中提到的雙重請求死鎖,注意,需要關閉的只是當前處理器上的中斷,如果中斷發生在不同的處理器上,即使中斷處理程序在同一鎖上自旋,也不會妨礙鎖的持有者(在不同處理器上)最終釋放鎖。

自旋鎖的簡單理解:
理解自旋鎖最簡單的方法是把它作為一個變數看待,該變數把一個臨界區或者標記為「我當前正在運行,請稍等一會」或者標記為「我當前不在運行,可以被使用」。如果A執行單元首先進入常式,它將持有自旋鎖,當B執行單元試圖進入同一個常式時,將獲知自旋鎖已被持有,需等到A執行單元釋放後才能進入。

自旋鎖的API函數:

其實介紹的幾種信號量和互斥機制,其底層源碼都是使用自旋鎖,可以理解為自旋鎖的再包裝。所以從這里就可以理解為什麼自旋鎖通常可以提供比信號量更高的性能。
自旋鎖是一個互斥設備,他只能會兩個值:「鎖定」和「解鎖」。它通常實現為某個整數之中的單個位。
「測試並設置」的操作必須以原子方式完成。
任何時候,只要內核代碼擁有自旋鎖,在相關CPU上的搶占就會被禁止。
適用於自旋鎖的核心規則:
(1)任何擁有自旋鎖的代碼都必須使原子的,除服務中斷外(某些情況下也不能放棄CPU,如中斷服務也要獲得自旋鎖。為了避免這種鎖陷阱,需要在擁有自旋鎖時禁止中斷),不能放棄CPU(如休眠,休眠可發生在許多無法預期的地方)。否則CPU將有可能永遠自旋下去(死機)。
(2)擁有自旋鎖的時間越短越好。

需 要強調的是,自旋鎖別設計用於多處理器的同步機制,對於單處理器(對於單處理器並且不可搶占的內核來說,自旋鎖什麼也不作),內核在編譯時不會引入自旋鎖 機制,對於可搶占的內核,它僅僅被用於設置內核的搶占機制是否開啟的一個開關,也就是說加鎖和解鎖實際變成了禁止或開啟內核搶占功能。如果內核不支持搶 占,那麼自旋鎖根本就不會編譯到內核中。
內核中使用spinlock_t類型來表示自旋鎖,它定義在:
typedef struct {
raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
unsigned int break_lock;
#endif
} spinlock_t;

對於不支持SMP的內核來說,struct raw_spinlock_t什麼也沒有,是一個空結構。對於支持多處理器的內核來說,struct raw_spinlock_t定義為
typedef struct {
unsigned int slock;
} raw_spinlock_t;

slock表示了自旋鎖的狀態,「1」表示自旋鎖處於解鎖狀態(UNLOCK),「0」表示自旋鎖處於上鎖狀態(LOCKED)。
break_lock表示當前是否由進程在等待自旋鎖,顯然,它只有在支持搶占的SMP內核上才起作用。
自旋鎖的實現是一個復雜的過程,說它復雜不是因為需要多少代碼或邏輯來實現它,其實它的實現代碼很少。自旋鎖的實現跟體系結構關系密切,核心代碼基本也是由匯編語言寫成,與體協結構相關的核心代碼都放在相關的目錄下,比如。對於我們驅動程序開發人員來說,我們沒有必要了解這么spinlock的內部細節,如果你對它感興趣,請參考閱讀Linux內核源代碼。對於我們驅動的spinlock介面,我們只需包括頭文件。在我們詳細的介紹spinlock的API之前,我們先來看看自旋鎖的一個基本使用格式:
#include
spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock(&lock);
....
spin_unlock(&lock);

從使用上來說,spinlock的API還很簡單的,一般我們會用的的API如下表,其實它們都是定義在中的宏介面,真正的實現在中
#include
SPIN_LOCK_UNLOCKED
DEFINE_SPINLOCK
spin_lock_init( spinlock_t *)
spin_lock(spinlock_t *)
spin_unlock(spinlock_t *)
spin_lock_irq(spinlock_t *)
spin_unlock_irq(spinlock_t *)
spin_lock_irqsace(spinlock_t *,unsigned long flags)
spin_unlock_irqsace(spinlock_t *, unsigned long flags)
spin_trylock(spinlock_t *)
spin_is_locked(spinlock_t *)

• 初始化
spinlock有兩種初始化形式,一種是靜態初始化,一種是動態初始化。對於靜態的spinlock對象,我們用 SPIN_LOCK_UNLOCKED來初始化,它是一個宏。當然,我們也可以把聲明spinlock和初始化它放在一起做,這就是 DEFINE_SPINLOCK宏的工作,因此,下面的兩行代碼是等價的。
DEFINE_SPINLOCK (lock);
spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock_init 函數一般用來初始化動態創建的spinlock_t對象,它的參數是一個指向spinlock_t對象的指針。當然,它也可以初始化一個靜態的沒有初始化的spinlock_t對象。
spinlock_t *lock
......
spin_lock_init(lock);

• 獲取鎖
內核提供了三個函數用於獲取一個自旋鎖。
spin_lock:獲取指定的自旋鎖。
spin_lock_irq:禁止本地中斷並獲取自旋鎖。
spin_lock_irqsace:保存本地中斷狀態,禁止本地中斷並獲取自旋鎖,返回本地中斷狀態。

自旋鎖是可以使用在中斷處理程序中的,這時需要使用具有關閉本地中斷功能的函數,我們推薦使用 spin_lock_irqsave,因為它會保存加鎖前的中斷標志,這樣就會正確恢復解鎖時的中斷標志。如果spin_lock_irq在加鎖時中斷是關閉的,那麼在解鎖時就會錯誤的開啟中斷。

另外兩個同自旋鎖獲取相關的函數是:
spin_trylock():嘗試獲取自旋鎖,如果獲取失敗則立即返回非0值,否則返回0。
spin_is_locked():判斷指定的自旋鎖是否已經被獲取了。如果是則返回非0,否則,返回0。
• 釋放鎖
同獲取鎖相對應,內核提供了三個相對的函數來釋放自旋鎖。
spin_unlock:釋放指定的自旋鎖。
spin_unlock_irq:釋放自旋鎖並激活本地中斷。
spin_unlock_irqsave:釋放自旋鎖,並恢復保存的本地中斷狀態。

五、讀寫自旋鎖
如 果臨界區保護的數據是可讀可寫的,那麼只要沒有寫操作,對於讀是可以支持並發操作的。對於這種只要求寫操作是互斥的需求,如果還是使用自旋鎖顯然是無法滿 足這個要求(對於讀操作實在是太浪費了)。為此內核提供了另一種鎖-讀寫自旋鎖,讀自旋鎖也叫共享自旋鎖,寫自旋鎖也叫排他自旋鎖。
讀寫自旋鎖是一種比自旋鎖粒度更小的鎖機制,它保留了「自旋」的概念,但是在寫操作方面,只能最多有一個寫進程,在讀操作方面,同時可以有多個讀執行單元,當然,讀和寫也不能同時進行。
讀寫自旋鎖的使用也普通自旋鎖的使用很類似,首先要初始化讀寫自旋鎖對象:
// 靜態初始化
rwlock_t rwlock = RW_LOCK_UNLOCKED;
//動態初始化
rwlock_t *rwlock;
...
rw_lock_init(rwlock);

在讀操作代碼里對共享數據獲取讀自旋鎖:
read_lock(&rwlock);
...
read_unlock(&rwlock);

在寫操作代碼里為共享數據獲取寫自旋鎖:
write_lock(&rwlock);
...
write_unlock(&rwlock);

需要注意的是,如果有大量的寫操作,會使寫操作自旋在寫自旋鎖上而處於寫飢餓狀態(等待讀自旋鎖的全部釋放),因為讀自旋鎖會自由的獲取讀自旋鎖。

讀寫自旋鎖的函數類似於普通自旋鎖,這里就不一一介紹了,我們把它列在下面的表中。
RW_LOCK_UNLOCKED
rw_lock_init(rwlock_t *)
read_lock(rwlock_t *)
read_unlock(rwlock_t *)
read_lock_irq(rwlock_t *)
read_unlock_irq(rwlock_t *)
read_lock_irqsave(rwlock_t *, unsigned long)
read_unlock_irqsave(rwlock_t *, unsigned long)
write_lock(rwlock_t *)
write_unlock(rwlock_t *)
write_lock_irq(rwlock_t *)
write_unlock_irq(rwlock_t *)
write_lock_irqsave(rwlock_t *, unsigned long)
write_unlock_irqsave(rwlock_t *, unsigned long)
rw_is_locked(rwlock_t *)
六、順序瑣
順序瑣(seqlock)是對讀寫鎖的一種優化,若使用順序瑣,讀執行單元絕不會被寫執行單元阻塞,也就是說,讀執行單元可以在寫執行單元對被順序瑣保護的共享資源進行寫操作時仍然可以繼續讀,而不必等待寫執行單元完成寫操作,寫執行單元也不需要等待所有讀執行單元完成讀操作才去進行寫操作。
但是,寫執行單元與寫執行單元之間仍然是互斥的,即如果有寫執行單元在進行寫操作,其它寫執行單元必須自旋在哪裡,直到寫執行單元釋放了順序瑣。
如果讀執行單元在讀操作期間,寫執行單元已經發生了寫操作,那麼,讀執行單元必須重新讀取數據,以便確保得到的數據是完整的,這種鎖在讀寫同時進行的概率比較小時,性能是非常好的,而且它允許讀寫同時進行,因而更大的提高了並發性,
注意,順序瑣由一個限制,就是它必須被保護的共享資源不含有指針,因為寫執行單元可能使得指針失效,但讀執行單元如果正要訪問該指針,將導致Oops。
七、信號量
Linux中的信號量是一種睡眠鎖,如果有一個任務試圖獲得一個已經被佔用的信號量時,信號量會將其推進一個等待隊列,然後讓其睡眠,這時處理器能重獲自由,從而去執行其它代碼,當持有信號量的進程將信號量釋放後,處於等待隊列中的哪個任務被喚醒,並獲得該信號量。
信號量,或旗標,就是我們在操作系統里學習的經典的P/V原語操作。
P:如果信號量值大於0,則遞減信號量的值,程序繼續執行,否則,睡眠等待信號量大於0。
V:遞增信號量的值,如果遞增的信號量的值大於0,則喚醒等待的進程。

信號量的值確定了同時可以有多少個進程可以同時進入臨界區,如果信號量的初始值始1,這信號量就是互斥信號量(MUTEX)。對於大於1的非0值信號量,也可稱為計數信號量(counting semaphore)。對於一般的驅動程序使用的信號量都是互斥信號量。
類似於自旋鎖,信號量的實現也與體系結構密切相關,具體的實現定義在頭文件中,對於x86_32系統來說,它的定義如下:
struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
};

信號量的初始值count是atomic_t類型的,這是一個原子操作類型,它也是一個內核同步技術,可見信號量是基於原子操作的。我們會在後面原子操作部分對原子操作做詳細介紹。

信號量的使用類似於自旋鎖,包括創建、獲取和釋放。我們還是來先展示信號量的基本使用形式:
static DECLARE_MUTEX(my_sem);
......
if (down_interruptible(&my_sem))

{
return -ERESTARTSYS;
}
......
up(&my_sem)

Linux內核中的信號量函數介面如下:
static DECLARE_SEMAPHORE_GENERIC(name, count);
static DECLARE_MUTEX(name);
seam_init(struct semaphore *, int);
init_MUTEX(struct semaphore *);
init_MUTEX_LOCKED(struct semaphore *)
down_interruptible(struct semaphore *);
down(struct semaphore *)
down_trylock(struct semaphore *)
up(struct semaphore *)
• 初始化信號量
信號量的初始化包括靜態初始化和動態初始化。靜態初始化用於靜態的聲明並初始化信號量。
static DECLARE_SEMAPHORE_GENERIC(name, count);
static DECLARE_MUTEX(name);

對於動態聲明或創建的信號量,可以使用如下函數進行初始化:
seam_init(sem, count);
init_MUTEX(sem);
init_MUTEX_LOCKED(struct semaphore *)

顯然,帶有MUTEX的函數始初始化互斥信號量。LOCKED則初始化信號量為鎖狀態。
• 使用信號量
信號量初始化完成後我們就可以使用它了
down_interruptible(struct semaphore *);
down(struct semaphore *)
down_trylock(struct semaphore *)
up(struct semaphore *)

down函數會嘗試獲取指定的信號量,如果信號量已經被使用了,則進程進入不可中斷的睡眠狀態。down_interruptible則會使進程進入可中斷的睡眠狀態。關於進程狀態的詳細細節,我們在內核的進程管理里在做詳細介紹。

down_trylock嘗試獲取信號量, 如果獲取成功則返回0,失敗則會立即返回非0。

當退出臨界區時使用up函數釋放信號量,如果信號量上的睡眠隊列不為空,則喚醒其中一個等待進程。

八、讀寫信號量
類似於自旋鎖,信號量也有讀寫信號量。讀寫信號量API定義在頭文件中,它的定義其實也是體系結構相關的,因此具體實現定義在頭文件中,以下是x86的例子:
struct rw_semaphore {
signed long count;
spinlock_t wait_lock;
struct list_head wait_list;
};

Ⅳ 分析怎樣實現的對共享存儲區的互斥和同步

你說的這個是遠程監控和備份,需要在PC1上登錄客戶端軟體通過花生殼或其他域名伺服器域名解析出去,然後你在PC2上面通過解析出來的域名登錄上去進行監控和存儲即可。不過遠程監控效果很一般,圖像也不連續,除非你是光線上網這樣才會好一點。

Ⅵ 如何提高MySQL並發能力的思路

1、使用行級別鎖,避免表級別或頁級別鎖
盡量使用支持行級別鎖的存儲引擎,如InnoDB;只在讀操作顯著多於寫作的場景中(如數據倉庫類的應用)使用表級別鎖的存儲引擎,如MyISAM;。
2、降低熱巨鎖(hot gaint lock)出現的可能性以盡可能避免全局互斥量
臨界區(僅允許單一線程訪問的資源)會嚴重降低MySQL系統並發性;InnoDB緩沖池(buffer pool)、數據字典等都是常見的臨界區;幸運的是,新版本的InnoDB已經能夠較好的運行於多核處理器,支持使用 innodb_buffer_pool_instances伺服器變數建立多個緩沖池實例,每個緩沖池實例分別自我管理空閑列表、列表刷寫、LRU以及其它跟緩沖池相關的數據結構,並通過各自的互斥鎖進行保護。
3、並行運行多個I/O線程
通過innodb_io_capacity伺服器變數等增加磁碟I/O線程的數量可以提高前端操作(如SELECT)的性能,不過,磁碟I/O線程的數量不應該超過磁碟的IOPS(7200RPM的單塊硬體的IOPS數量一般為100個左右)。
此外,非同步I/O也可以在一定程度上提高系統的並發能力,在Linux系統上,可以通過將MySQL的伺服器變數innodb_use_native_aio的值設定為ON設定InnoDB可以使用Linux的非同步I/O子系統。
4、並行後端任務
默認情況下,MySQL的清寫(purge)操作(用於移除帶刪除標記的記錄)由InnoDB的主線程完成,這可以降低內部資源競爭發生的概率,進而增強MySQL服務伸縮能力。不過,隨著InnoDB內部各式各樣的競爭越來越多,這種設置帶來的性能優勢已幾乎不值一提,因此,生產環境中應該通過為innodb_purge_threads伺服器變數設定為ON將主線程與清寫線程分開運行。
5、單線程復制模型中的SQL線程是一個熱區
在從伺服器上並行運行多個SQL線程可有效提高MySQL從伺服器性能,MySQL 5.6支持多線程復制(每庫一個復制線程);

Ⅶ 6. 臨界區是指並發進程中訪問共享變數的()段. A,管理信息 B,信息存儲 C,數據 D,程序

一、單項選擇題(每題1分,共20分) 1.操作系統的發展過程是( C )

C、管理程序,原始操作系統,操作系統

2.用戶程序中的輸入、輸出操作實際上是由(B、操作系統 )完成。

3.進程調度的對象和任務分別是( C )。

C、進程,從就緒隊列中按一定的調度策略選擇一個進程佔用CPU 4.支持程序浮動的地址轉換機制是( A、動態重定位 )

5.在可變分區存儲管理中,最優適應分配演算法要求對空閑區表項按(C、尺寸從小到大)進行排列。

6.設計批處理多道系統時,首先要考慮的是( 系統效率和吞吐量 )。 7.當進程因時間片用完而讓出處理機時,該進程應轉變為( b )狀態。

A、等待 B、就緒 C、運行 D、完成 8.文件的保密是指防止文件被( c )。

A、篡改 B、破壞 C、竊取 D、刪除

9.若系統中有五個並發進程涉及某個相同的變數A,則變數A的相關臨界區是由( d )

臨界區構成。

A、2個 B、3個 C、4個 D、5個

10.按邏輯結構劃分,文件主要有兩類:(記錄式文件 )和流式文件。 A、記錄式文件 B、網狀文件 C、索引文件 D、流式文件
11.UNIX中的文件系統採用(、流式文件 )。

A、網狀文件 B、記錄式文件 C、索引文件 D、流式文件 12.文件系統的主要目的是(A、實現對文件的按名存取 )。 13.文件系統中用( D、目錄
)管理文件。

14.為了允許不同用戶的文件具有相同的文件名,通常在文件系統中採用(B、多級目

錄 )。

15.在多進程的並發系統中,肯定不會因競爭(C、CPU )而產生死鎖。

16.一種既有利於短小作業又兼顧到長作業的作業調度演算法是( C、最高響應比優先
)。17.兩個進程合作完成一個任務。在並發執行中,一個進程要等待其合作夥伴發來消息,或

者建立某個條件後再向前執行,這種制約性合作關系被稱為進程的( B、同步 )。18.當每類資源只有一個個體時,下列說法中不正確的是( )。

A、有環必死鎖 B、死鎖必有環

C、有環不一定死鎖 D、被鎖者一定全在環中

19.數據文件存放在到存儲介質上時,採用的邏輯組織形式是與(A、文件邏輯結構 )

有關的。

20.在單處理器的多進程系統中,進程什麼時候佔用處理器和能佔用多長時間,取決於(B、進程自身和進程調度策略 )。
二、填空題(每空2分,共20分)

1.若信號量S的初值定義為10,則在S上調用了16次P操作和15次V操作後S的值應

該為( 9 )。

2.進程調度的方式通常有(搶占 )和(非搶占)兩種方式。

3.每個索引文件都必須有一張( 索引結點 )表,其中的地址登記項用來指出文件在外存

上的位置信息。

4.在一請求分頁系統中,假如一個作業的頁面走向為:4、3、2、1、4、3、5、4、3、2、1、

5,當分配給該作業的物理塊數為4時(開始時沒有裝入頁面),採用LRU頁面淘汰演算法將產生( 8 )次缺頁中斷。

5.信號量被廣泛用於三個目的是( 同步 )、( 互斥 )和描述前趨關系。

6.程序並發執行時的特徵是( 間斷性 )、( 失去了封閉性 )、( 不可再現性 )和獨立性。 三、判斷題(每題1分,共10分)

( T )1.文件系統中分配存儲空間的基本單位不是記錄。 ( F )2.具有多道功能的操作系統一定是多用戶操作系統。

( T )3.虛擬存儲器是由操作系統提供的一個假想的特大存儲器,它並不是實際的內存,其大小可比內存空間大得多。

( T )4.批處理系統的(主要優點)是系統的吞吐量大、資源利用率高、系統的開銷較小。 ( F )5.文件系統中源程序是有結構的記錄式文件。

( F )6.即使在多道程序環境下,普通用戶也能設計用內存物理地址直接訪問內存的程序。 ( F
)7.順序文件適合建立在順序存儲設備上,而不適合建立在磁碟上。

( T )8.SPOOLing系統實現設備管理的虛擬技術,即:將獨占設備改造為共享設備。它由專門負責I/O的常駐內存進程以及輸入、輸出井組成。

( F )9.系統調用是操作系統與外界程序之間的介面,它屬於核心程序。在層次結構設計中,它最靠近硬體。

( F )10.若系統中存在一個循環等待的進程集合,則必定會死鎖。 四、程序與演算法(共10分)

設有一緩沖池P,P中含有20個可用緩沖區,一個輸入進程將外部數據讀入P,另有一

個輸出進程將P中數據取出並輸出。若講程每次操作均以一個緩沖區為單位,試用記錄型信號量寫出兩個進程的同步演算法,要求寫出信號量的初值。 解:

semaphore mutex=1; semaphore empty=20; semaphore full=0; int in,out = 0;
item p [20]; void Procer(){ while(ture){

procer an item in nextp; wait(empty); wait(mutex); p[in] := nextp; in :=
(in+1) mod 20; signal(mutex); signal(full); } }

void Consumer(){ while(ture){ wait(full); wait(mutex); nextc := p[out]; out
:= (out+1) mod 20; signal(mutex); signal(empty); } }

五、問答題(共16分)

某系統有A、B、C、D四類資源可供五個進程P1、P2、P3、P4、P5共享。系統對這四類資源的擁有量為:A類3個、B類14個、C類12個、D類12個。進程對資源的需求和分配

情況如下:

按銀行家演算法回答下列問題:

(1)現在系統中的各類資源還剩餘多少?(4分) (2)現在系統是否處於安全狀態?為什麼?(6分)

(3)如果現在進程P2提出需要A類資源0個、B類資源4個、C類資源2個和D類資源0個,系統能否去滿足它的請求?請說明原因。(6)

(1)A:1;B:5;C:2;D:0 (2)need矩陣為:P1 0 0 0 0 P2 0 7 5 0 P3 1 0 0 2 P4 0 0 2 0
P5 0 6 4 2

存在安全序列,如P1,P3

,P4,P5,P2,所以安全

(3)能,因為試探分配後,可用資源為1,1,0,0。可找到安全序列,所以可分配。六、計算題(第1題6分;第2題10分;第3題8分;共24分)

1、某虛擬存儲器的用戶編程空間共32個頁面,每頁為1KB,內存為16KB。假定某時刻一用戶頁表中已調入內存的頁面的頁號和物理塊號的對照表如下:

則邏輯地址0A5D(H)所對應的物理地址是什麼?(6分)

0A5D(H)=0000 1010 0101 1101

2號頁對應4號塊,所以物理地址是0001 0010 0101 1101

即125D(H)。

2、設有三道作業,它們的提交時間及執行時間由下表給出:

作業號 提交時間 執行時間

1 8.5 2.0

2 9.2 1.6

3 9.4 0.5

試計算在單道程序環境下,採用先來先服務調度演算法和最短作業優先調度演算法時的平均周轉時間
(時間單位:小時,以十進制進行計算;要求寫出計算過程)(10分)

FCFS: 作業號 提交時間 執行時間 開始時間 完成時間 周轉時間

1 8.5 2.0 8.5 10.5 2.0

2 9.2 1.6 10.5 12.1 2.9

3 9.4 0.5 12.1 12.6 3.2

平均周轉時間=(2.0+2.9+3.2)/3=2.7(小時)

SJF: 作業號 提交時間 執行時間 開始時間 完成時間 周轉時間

1 8.5 2.0 8.5 10.5 2.0

2 9.2 1.6 11.0 12.6 3.4

3 9.4 0.5 10.5 11.0 1.6

平均周轉時間=(2.0+3.4+1.6)/3=2.3(小時)

3、假定當前磁頭位於100號磁軌,進程對磁軌的請求序列依次為55,58,39,18,90,160,150,38,180。當採用先來先服務和最短尋道時間優先演算法時,總的移動的磁軌數分別是多少?(請給出尋道次序和每步移動磁軌數)(8分)

FCFS: 服務序列依次為:55,58,39,18,90,160,150,38,180

移動的磁軌數分別是: 45, 3, 19, 21, 72, 70, 10, 112,142

總的移動的磁軌數是:494

SSTF: 服務序列依次為:90,58,55,39,38,18,150,160,180

移動的磁軌數分別是: 10, 32, 3, 16, 1, 20, 132, 10, 20

總的移動的磁軌數是:244

Ⅷ 驅動裡面為什麼要有並發,互斥的控制如何實現

驅動裡面為什麼要有並發、互斥的控制?如何實現?講個例子? 並發(concurrency)指的是多個執行單元同時、並行被執行,而並發的執行單元對 共 享資源(硬體資源和軟體上的全局變數、靜態變數等)的訪問則很容易導致競態(race conditions) 。 解決競態問題的途徑是保證對共享資源的互斥訪問, 所謂互斥訪問就是指一個執行單 元 在訪問共享資源的時候,其他的執行單元都被禁止訪問。 訪問共享資源的代碼區域被稱為臨界區, 臨界區需要以某種互斥機 制加以保護, 中斷屏蔽, 原子操作,自旋鎖,和信號量都是 linux 設備驅動中可採用的互斥途徑。

Ⅸ 如何利用信號量機制實現多進程訪問臨界資源

進程互斥 定義:兩個或兩個以上的進程,不能同時進入關於同一組共享變數的臨界區域,否則可能發生與時間有關的錯誤,這種現象被稱作進程互斥.
在多道程序環境下,存在著臨界資源,它是指多進程存在時必須互斥訪問的資源。也就是某一時刻不允許多個進程同時訪問,只能單個進程的訪問。我們把這些程序的片段稱作臨界區或臨界段,它存在的目的是有效的防止競爭條件又能保證最大化使用共享數據。而這些並發進程必須有好的解決方案,才能防止出現以下情況:多個進程同時處於臨界區,臨界區外的進程阻塞其他的進程,有些進程在臨界區外無休止的等待。除此以外,這些方案還不能對CPU的速度和數目做出任何的假設。只有滿足了這些條件,才是一個好的解決方案。
訪問臨界資源的循環進程可以這樣來描述:
Repeat
entry section
Critical sections;
exit section
Remainder sectioni;
Until false
為實現進程互斥,可以利用軟體的方法,也可以在系統中設置專門的同步機制來協調多個進程,但是所有的同步機制應該遵循四大准則:
1.空閑讓進 當臨界資源處於空閑狀態,允許一個請求進入臨界區的進程立即進入臨界區,從 而有效的利用資源。
2.忙則等待 已經有進程進入臨界區時,意味著相應的臨界資源正在被訪問,所以其他准備進 入臨界區的進程必須等待,來保證多進程互斥。
3.有限等待 對要求訪問臨界資源的進程,應該保證該進程能在有效的時間內進入臨界區,防 止死等狀態。
4.讓權等待 當進程不能進入臨界區,應該立即釋放處理機,防止進程忙等待。
早期解決進程互斥問題有軟體的方法和硬體的方法,如:嚴格輪換法,Peterson的解決方案,TSL指令,Swap指令都可以實現進程的互斥,不過它們都有一定的缺陷,這里就不一一詳細說明,而後來Kijkstra提出的信號量機制則更好的解決了互斥問題。