C++ 線程同步互斥量Mutex
一、互斥對象
互斥對象屬于系統內核對象,它能夠使線程擁有對某個資源的絕對訪問權。互斥對象主要包含使用數量、線程ID、遞歸計數器等。線程ID表示當前擁有互斥對象的線程,遞歸計數器表示線程擁有互斥對象的次數。
1、當互斥對象的線程ID為0時,表示互斥對象不被任何線程所擁有,此時系統會發出該互斥對象的通知信號,等待該互斥對象的其他線程中的某一個線程會擁有該互斥對象,同時,互斥對象的線程ID為當前擁有該互斥對象的線程的線程ID。
2、當互斥對象的線程ID不為0時,表示當前有線程擁有該互斥對象。系統不會發出互斥對象的通知信號。其他等待互斥對象的線程繼續等待,直到擁有改互斥對象的線程釋放互斥對象的擁有權。
二、創建互斥對象
CreateMutex函數創建一個互斥對象,成功返回該互斥對象的句柄,失敗返回NULL。
HANDLE WINAPI CreateMutex(
__in LPSECURITY_ATTRIBUTES lpMutexAttributes,//互斥對象的安全屬性
__in BOOL bInitialOwner,//互斥對象的初始狀態;TRUE表示互斥對象的線程ID為當前調度線程的線程ID,當前創建互斥對象的線程具有他的擁有權,互斥對象的遞歸計數器為1
__in LPCTSTR lpName//互斥對象的名稱,NULL表示創建一個匿名的互斥對象
);
當某一個線程擁有互斥對象所有權后,就可以獨占系統中受保護的資源;不再需要資源的時候,可以調用ReleaseMutex函數釋放互斥對象的所有權;ReleaseMutex函數每調用一次,遞歸計數器減1;直到減到0時才釋放互斥對象,互斥對象才變為通知狀態。
BOOL WINAPI ReleaseMutex(
__in HANDLE hMutex
);
等待互斥對象WaitForSingleObject函數DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,//等待內核對象句柄
__in DWORD dwMilliseconds//等待時間,INFINITE表示無限等待
);
失敗返回WAIT_FAILED;
三、賣票系統試題
有三個賣票的位置;賣100張票;
CMutex.h文件
#ifndef _CMUTEX_H__
#define _CMUTEX_H__
class CMutex
{
public:
CMutex();
~CMutex();
void StartThread();
static DWORD __stdcall ThreadFun1(LPVOID lParam);//賣家1
static DWORD __stdcall ThreadFun2(LPVOID lParam);//賣家2
static DWORD __stdcall ThreadFun3(LPVOID lParam);//賣家3
private:
HANDLE m_hThread1;
HANDLE m_hThread2;
HANDLE m_hThread3;
HANDLE hMutex;//互斥對象
static int nTickets;//票的總數
};
#endif
#include "stdafx.h"
#include "CMutex.h"
int CMutex::nTickets = 100;
CMutex::CMutex()
{
hMutex = CreateMutex(NULL, FALSE, L"mutex");
}
CMutex::~CMutex()
{
if (NULL != hMutex)
{
CloseHandle(hMutex);
hMutex = NULL;
}
if (NULL != m_hThread1)
{
CloseHandle(m_hThread1);
m_hThread1 = NULL;
}
if (NULL != m_hThread2)
{
CloseHandle(m_hThread2);
m_hThread2 = NULL;
}
if (NULL != m_hThread3)
{
CloseHandle(m_hThread3);
m_hThread3 = NULL;
}
}
DWORD __stdcall CMutex::ThreadFun1(LPVOID lParam)
{
DWORD dRet = TRUE;
CMutex * pThis = (CMutex*)lParam;
while (1)
{
WaitForSingleObject(pThis->hMutex, INFINITE);
if (pThis->nTickets < 1)
{
break;
}
cout<<"ThreadFun1 賣出票:"<<pThis->nTickets--<<endl;
ReleaseMutex(pThis->hMutex);
}
return dRet;
}
DWORD __stdcall CMutex::ThreadFun2(LPVOID lParam)
{
DWORD dRet = TRUE;
CMutex * pThis = (CMutex*)lParam;
while (1)
{
WaitForSingleObject(pThis->hMutex, INFINITE);
if (pThis->nTickets < 1)
{
break;
}
cout<<"ThreadFun2 賣出票:"<<pThis->nTickets--<<endl;
ReleaseMutex(pThis->hMutex);
}
return dRet;
}
DWORD __stdcall CMutex::ThreadFun3(LPVOID lParam)
{
DWORD dRet = TRUE;
CMutex * pThis = (CMutex*)lParam;
while (1)
{
WaitForSingleObject(pThis->hMutex, INFINITE);
if (pThis->nTickets < 1)
{
break;
}
cout<<"ThreadFun3 賣出票:"<<pThis->nTickets--<<endl;
ReleaseMutex(pThis->hMutex);
}
return dRet;
}
void CMutex::StartThread()
{
m_hThread1 = CreateThread(NULL, 0, &CMutex::ThreadFun1, this, 0, NULL);
m_hThread2 = CreateThread(NULL, 0, &CMutex::ThreadFun2, this, 0, NULL);
m_hThread3 = CreateThread(NULL, 0, &CMutex::ThreadFun3, this, 0, NULL);
}
main.cpp
// Mutex.cpp : 定義控制臺應用程序的入口點。
//
#include "stdafx.h"
#include "CMutex.h"
int _tmain(int argc, _TCHAR* argv[])
{
CMutex myMutex;
myMutex.StartThread();
Sleep(4000);
system("pause");
return 0;
}
結果
如果不加互斥對象,將可能出現賣出0這一張票的可能性;
智能推薦
完整的C++ 靜態單例代碼(帶互斥量Mutex)
今天又復習了一下靜態單例,但是以前只是知道實現靜態單例的原理以及注意事項,寫的代碼也沒有運行過,因為靜態單例涉及到了多線程的知識, 并且我以前 只在Linux上用C語言的多線程,對windows下的C++多線程不了解。 帶有多線程保護的靜態單例原理我不細講,網上一大堆,能運行的代碼 我沒找到(或者 我感覺那代碼很亂,不符合自己口味) 今天下決心寫一個能夠運行的 帶有多線程保護的(帶互斥量)的靜態單...
linux c 線程間同步(通信)的幾種方法--互斥鎖,條件變量,信號量,讀寫鎖
Linux下提供了多種方式來處理線程同步,最常用的是互斥鎖、條件變量、信號量和讀寫鎖。 下面是思維導圖: 一、互斥鎖(mutex) 鎖機制是同一時刻只允許一個線程執行一個關鍵部分的代碼。 1 . 初始化鎖 其中參數 mutexattr 用于指定鎖的屬性(見下),如果為NULL則使用缺省屬性。 互斥鎖的屬性在創建鎖的時候指定,在Lin...
【Linux】深入理解線程(線程同步、互斥量mutex、死鎖、讀寫鎖、條件變量、信號量)
一、同步概念 1、線程同步: 同步即協同步調,按預定的先后次序運行。 線程同步,只一個線程發出某一功能調用時,在沒有得到結果之前,該調用不返回。同時,其他線程為保證數據一致性,不...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
猜你喜歡
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...