windows 之 互斥鎖 Mutex

線程間的互斥:

eg:


//共享資源
static int num = 0;
//互斥鎖
HANDLE  g_Mutex = CreateMutex(NULL, FALSE, NULL);
 
//子線程函數  
unsigned int __stdcall ChildThreadFunc(LPVOID pM)
{
	while (true)
	{
		Sleep(500);
 
		WaitForSingleObject(g_Mutex, INFINITE);//等待互斥量  INFINITE表示永遠等待
		num++;
		printf("num:%d\n", num);
		ReleaseMutex(g_Mutex);
	}
	return 0;
}
 
int main()
{
	HANDLE handle[5] = { 0 };
 
	for (int i = 0; i < 5; i++)
	{
		handle[i] = (HANDLE)_beginthreadex(NULL, 0, ChildThreadFunc, NULL, 0, NULL);
	}
	
	//阻塞等待
	for (int i = 0; i < 5; i++)
	{
		WaitForSingleObject(handle[i], -1);
	}
 
	printf("主線程 num:%d\n", num);
	getchar();
	return 0;
}

進程中使用互斥量與在線程中使用其原理和操作流程相同,唯一區別在於線程中可以不爲互斥量指定名稱,而在進程中需要指定名稱,由此其他進程可以根據名稱獲取該互斥量的句柄。

eg: 兩個進程共享名字爲pmutex的互斥量

其中一個進程代碼:

#include <iostream>
#include <windows.h>
using namespace std;
 
 
int main()
{
	// 若不存在名爲"pmutex"的互斥量則創建它;否則獲取其句柄
    // Mutex 可以跨進程使用,所以其名稱對整個系統而言是全局的,所以命名不要過於普通,類似:Mutex、Object 等。
    HANDLE hMutex = CreateMutex(NULL, false, "mypmutex");
    if(NULL == hMutex)
    {
        cout<<"create mutex error "<<GetLastError()<<endl;
        return 0;
    }
    else 
    {
        cout<<" create mutex success:"<<hMutex<<endl;
    }
 
     for(int i = 0;i<10; i++)
    {
		// 申請對互斥量的佔有
        DWORD  d  = WaitForSingleObject(hMutex, INFINITE);
        if(WAIT_OBJECT_0 == d)
        {
			// 模擬對公共內存/文件的操作
            cout<<"begin sleep"<<endl;
            Sleep(2000);
            cout<<"process 1"<<endl;
			
			// 操作完畢,釋放對互斥量的佔有
            if(ReleaseMutex(hMutex)!=0)
            {
                cout<<"reslease ok"<<endl;
            }
            else
            {
                cout<<"reslease failed"<<endl;
            }
        }
        if(WAIT_ABANDONED == d)
        {
            cout<<"WAIT_ABANDONED"<<endl;
        }
        if(WAIT_FAILED ==d)
        {
            cout<<"mutex error"<<endl;
        }
        Sleep(2000);
    }
	
	// 釋放互斥量
    CloseHandle(hMutex);
	hMutex = NULL;
    return 0;
}

另一個進程代碼:

#include <iostream>
#include <windows.h>
using namespace std;
 
 
int main()
{
	// 若不存在名爲"pmutex"的互斥量則創建它;否則獲取其句柄
    HANDLE hMutex = CreateMutex(NULL, false, "mypmutex");
    if(NULL == hMutex)
    {
        cout<<"create mutex error "<<GetLastError()<<endl;
        return 0;
    }
    else 
    {
        cout<<" create mutex success:"<<hMutex<<endl;
    }
 
     for(int i = 0;i<10; i++)
    {
		// 申請對互斥量的佔有
        DWORD  d  = WaitForSingleObject(hMutex, INFINITE);
        if(WAIT_OBJECT_0 == d)
        {
			// 模擬對公共內存/文件的操作
            cout<<"begin sleep"<<endl;
            Sleep(2000);
            cout<<"process 2"<<endl;
			
			// 操作完畢,釋放對互斥量的佔有
            if(ReleaseMutex(hMutex)!=0)
            {
                cout<<"reslease ok"<<endl;
            }
            else
            {
                cout<<"reslease failed"<<endl;
            }
        }
        if(WAIT_ABANDONED == d)
        {
            cout<<"WAIT_ABANDONED"<<endl;
        }
        if(WAIT_FAILED ==d)
        {
            cout<<"mutex error"<<endl;
        }
        Sleep(2000);
    }
	
	// 釋放互斥量
    CloseHandle(hMutex);
	hMutex = NULL;
    return 0;
}

總結步驟就是:

1、創建一個互斥器:CreateMutex;
2、打開一個已經存在的互斥器:OpenMutex;
3、獲得互斥器的擁有權:WaitForSingleObject、WaitForMultipleObjects ……(可能造成阻塞);
4、釋放互斥器的擁有權:ReleaseMutex;
5、關閉互斥器:CloseHandle;

Mutex是內核對象,陷入內核時間性能相對較差(與Critical Section相比)

WaitForMultipleObjects的例子:

#include <iostream>
#include <windows.h>
using namespace std;
 
HANDLE  g_hMutex = NULL;
const int g_Number = 3;
DWORD WINAPI ThreadProc1(__in  LPVOID lpParameter);
DWORD WINAPI ThreadProc2(__in  LPVOID lpParameter);
DWORD WINAPI ThreadProc3(__in  LPVOID lpParameter);
 
int main()
{
    g_hMutex = CreateMutex(NULL,FALSE,NULL);
    //TRUE代表主線程擁有互斥對象 但是主線程沒有釋放該對象  互斥對象誰擁有 誰釋放 
    // FLASE代表當前沒有線程擁有這個互斥對象
    HANDLE hThread[ g_Number ] = {0};
    int first = 1, second = 2, third = 3;
    hThread[ 0 ] = CreateThread(NULL,0,ThreadProc1,(LPVOID)first,0,NULL);
    hThread[ 1 ] = CreateThread(NULL,0,ThreadProc2,(LPVOID)second,0,NULL);
    hThread[ 2 ] = CreateThread(NULL,0,ThreadProc3,(LPVOID)third,0,NULL);
 
    WaitForMultipleObjects(g_Number,hThread,TRUE,INFINITE);
    CloseHandle( hThread[0] );
    CloseHandle( hThread[1] );
    CloseHandle( hThread[2] );
 
    CloseHandle( g_hMutex );
    return 0;
}
 
DWORD WINAPI ThreadProc1(__in  LPVOID lpParameter)
{
    WaitForSingleObject(g_hMutex, INFINITE);//等待互斥量
    cout<<(int)lpParameter<<endl;
    ReleaseMutex(g_hMutex);//釋放互斥量
    return 0;
}
 
DWORD WINAPI ThreadProc2(__in  LPVOID lpParameter)
{
    WaitForSingleObject(g_hMutex, INFINITE);//等待互斥量
    cout<<(int )lpParameter<<endl;
    ReleaseMutex(g_hMutex);//釋放互斥量
    return 0;
}
 
DWORD WINAPI ThreadProc3(__in  LPVOID lpParameter)
{
    WaitForSingleObject( g_hMutex, INFINITE);//等待互斥量
    cout<<(int)lpParameter<<endl;
    ReleaseMutex(g_hMutex);//釋放互斥量
    return 0;
}

DWORD WaitForMultipleObjects的(DWORD NCOUNT,CONST HANDLE * lpHandles,BOOLfWaitAll,DWORDdwMilliseconds);

四個參數分別是:

1. NCOUNT,DWORD類型,用於指定句柄數組的數量
2. lphObjects,指針類型,用於指定句柄數組的內存地址
3. fWaitAll,布爾類型,真表示函數等待所有指定句柄的對象有信號爲止,如果bWaitAll爲FALSE,則返回值減去WAIT_OBJECT_0表示滿足等待條件的對象的lpHandles數組索引。
4. dwTimeout,DWORD類型,用於指定等待時間的超時時間,單位毫秒,可以是INFINITE
當WaitForMultipleObjects等待多個內核對象的時候,如果它的bWaitAll參數設置爲false。其返回值包括WAIT_OBJECT_0 。如果同時有多個內核對象被觸發,這個函數返回的只是其中序號最小的那個。 

說白了就是,要有限還是無限時間地,全部還是隻要有一個完成就可以地,等待幾個並且是哪幾個內核對象完成。

通常可以根據WaitForMultipleObjects的返回值判斷是哪個序號的內核對象設置了信號:

HANDLE h[3]; 
h[0] = hProcess1; 
h[1] = hProcess2; 
h[2] = hProcess3; 
DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); 
switch(dw) 
{ 
case WAIT_FAILED: 
break; 
case WAIT_TIMEOUT: 
break; 
case WAIT_OBJECT_0 + 0; 
break; 
case WAIT_OBJECT_0 + 1; 
break; 
case WAIT_OBJECT_0 + 2; 
break; 
} 



但是上面的例子有一個問題,那就是比如hProcess1設置了信號,則switch必定返回WAIT_OBJECT_0+1

如果我們再一次獲取,及時hProcess1沒有產生信號,那麼也還是會返回WAIT_OBJECT_0+1,而無法判斷後面的內核對象的狀態

這個時候需要手動處理一下。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章