欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

四種進程或線程同步互斥的控制方法

系統 1933 0
四種 進程 或線程 同步 互斥 控制 方法

  很想整理一下自己對 進程 線程 同步 互斥 理解。正巧周六一個剛剛回到學校 同學請客吃飯。在吃飯 過程中,有兩個同學,為了一個問題爭論 面紅耳赤。一個認為.Net下 進程 線程控制模型更加合理。一個認為Java下 線程池策略比.Net 好。大家 話題一下轉到了 進程 線程 同步 互斥 控制問題上。回到家,想了想就寫了這個東東。

  現在流行 進程 線程 同步 互斥 控制機制,其實是由最原始最基本 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_Array[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. 通過互斥量可以指定資源被獨占 方式使用,但如果有下面一種情況通過互斥量就無法處理,比如現在一位用戶購買了一份三個并發訪問許可 數據庫系統,可以根據用戶購買 訪問許可數量來決定有多少個線程/ 進程 能同時進行數據庫操作,這時候如果利用互斥量就沒有辦法完成這個要求,信號燈對象可以說是一種資源計數器。

四種進程或線程同步互斥的控制方法


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 精品视频久久 | 91精品国啪老师啪 | 中国大陆高清aⅴ毛片 | 一级特黄欧美日韩免费视频 | 在线观看日本中文字幕 | 日韩精品www| 看一天影院 理论片 | 成人精品国产 | 小明看片成人永久在线观看 | 27xxoo无遮挡动态视频 | 天天插天天操天天射 | 亚洲午夜精品一级在线 | 国产精品久久久久久久 | 又爽又黄又无遮挡的激情视频免费 | 欧美午夜一艳片欧美精品 | 久久久久久久国产精品影院 | 国产视频aaa | www操操 | 久草新 | 亚洲天堂在线电影 | 日韩精品一区二区在线观看 | 欧美日屁 | 在线 丝袜 欧美 日韩 制服 | 欧美大码毛片在线播放 | 亚洲三级在线 | 久久精品人人做人人看最新章 | 中国一级毛片在线视频 | 久久aⅴ乱码一区二区三区 日韩精品一区二区在线观看 | 黑人精品欧美一区二区蜜桃 | 午夜影晥 | 国产大片在线观看 | 午夜影院福利社 | 欧美日韩国产一区二区三区不卡 | 日本视频一区在线观看免费 | 国产成人三级 | 三级成人在线 | 国内外成人免费视频 | 久久一本| 欧美鲁 | 天天艹天天干天天 | 日韩在线免费视频 |