互斥量和临界区差不多的,但是比临界区好理解,而且互斥量可以用于进程间的同步,所以我个人还是觉得相比于临界区而言,互斥量更加易用些。
其实这个演示程序的代码和前面使用临界区的代码差不多了,还是来简单的看一下吧:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MUTEX, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MUTEX);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
这是主函数,这个主函数没有一行代码是需要我们自己编写的,这是在生成Win32程序时,系统帮我们加上的,其实没有必要摆出来,不说废话来,来看看,窗口过程函数:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_CREATE:
m_gMutex = CreateMutex(NULL,FALSE,NULL);
hThreads[0] = CreateThread(NULL,0,WriteProc,NULL,0,NULL);
hThreads[1] = CreateThread(NULL,0,ReadProc,hWnd,0,NULL);
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
WaitForMultipleObjects(2,hThreads,TRUE,INFINITE);
CloseHandle(m_gMutex);
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
这个窗口过程函数响应了很多的消息,最重要的就是WM_CREATE,相应这个消息的时候,创建了一个互斥变量,并且启动了两个线程,一个是读线程,另一个是写线程。
下面来看看这两个线程入口函数:
DWORD WINAPI WriteProc(LPVOID pParm)
{
DWORD dw;
for (int j=0;j<10;j++)
{
dw = WaitForSingleObject(m_gMutex,INFINITE);
if (dw == WAIT_OBJECT_0) {
for (int i=0;i<10;i++)
iArray[i]=j;
ReleaseMutex(m_gMutex);
Sleep(1);
}
else{
break;
}
}
return 0;
}
DWORD WINAPI ReadProc(LPVOID pParm)
{
int aArray[10];
DWORD dw;
for (int i=0;i<10;i++)
{
//wait for the mutex to become signaled
dw = WaitForSingleObject(m_gMutex,INFINITE);
if (dw == WAIT_OBJECT_0) {
//mutex became unsignaled
for (int k=0;k<10;k++)
{
aArray[k]=iArray[k];
}
char str[255];
str[0]=0;
for (int j=0;j<10;j++)
{
int len=strlen(str);
wsprintf(&str[len],"%d",aArray[j]);
}
::MessageBox(NULL,str,"Thread Read Proc",MB_OK);// (HWND)param
ReleaseMutex(m_gMutex);
//mutex became signaled
}
else{
//the mutex is abandoned
break;
}
}
return 0;
}
从这两个函数可以看出,当写线程要往全局变量里面写数据的时候,首先需要 WaitForSingleObject(m_gMutex,INFINITE);这是干什么呢?这是在等待,等待m_gMutex变为有信号的状态,怎么理解这个有信号的状态呢?其实很简单,有信号就是我可以使用啊,等待的时刻就是我可以使用了,dw == WAIT_OBJECT_0怎么理解呢?因为WaitForSingleObject可能有其他的返回值,当返回值是这个的时候,才能说明我们等待的变量变为有信号了,这样的话,我们就可以开始使用cpu了,运行自己的程序吧,但是有一点不要忘记,使用完互斥变量之后,要记住ReleaseMutex,这样其他等待的线程才能开始使用cpu了,很简单的东西,却可以用来同步线程,其实同步线程并是不是想的那么麻烦。