第八章主要涉及到了用户模式同步。
第九章进行了内核对象同步。内核对象同步应用广,缺点是性能。
内核对象包括进程、线程以及作业(Job),这些都可以用来进行同步,有未触发状态和触发状态两种,创建时,未触发状态,终止时,触发状态。但是触发后不会再回到未触发状态。布尔量分别为false和true.
windows线程同步的内核对象有:事件、可等待计时器、信号量和互斥量。
等待函数使一个线程或进程,自愿进入等待状态,直到指定的内核对象被触发。有等待单个(waitforsingleObject)和多个(waitformultiObjects)。返回结果失败有WAIT_TIMEOUT,和WAIT_FAILED,成功有WAIT_OBJECT_0,如果是等待多个,则会从WAIT_OBJECT_0和(WAIT_OBJECT_0+dwCount-1)之间的任一个值。等待多个,可能等待一个内核对象被触发,也可能等待指定的全部内核被触发。
这里有个等待成功所引起的副作用,即自动重置事件对象,会在触发后,事件对象又变为非触发状态。这对于waitformultipleObjects有影响,因为WaitForMultipleObjects()是原子操作,
事件包含引用计数、重置事件布尔量(自动重置或者手动重置),是否被触发的布尔量。
自动重置,则调度一个等待该事件的线程。手动重置,则调度所有等待该事件的线程。
通常用途:线程A初始化,然而触发另一个线程B,让线程B执行剩余的工作。
具体是线程A初始化为未触发状态,初始化完成后,则触发事件。由于线程B一直等待该事件,线程B发现事件被触发后,于是线程B变成可调度。
几个函数:
1,创建事件内核对象。CreateEvent()
2,设置事件为触发状态.SetEvent()
3,设置事件为未触发状态。ResetEvent()。
列了个例子。服务器端和客户端互相触发事件。
代码及注释如下:
#include "../../trunk/CmmHdr.h"
#include <Windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <process.h>
#include "resource.h"
//客户端触发事件,服务器端的线程等待这个事件,以处理客户端请求
HANDLE g_heveRequestedSubmitted;
//服务器端触发事件,客户端线程等待这个事件,以处理服务器端返回的结果
HANDLE g_hevtResultReturned;
//服务器端和客户端共享缓存
TCHAR g_szSharedRequestAndResultBuffer[1024];
//客户端和服务器端约定的特殊字符串,以关闭服务器
TCHAR g_szServerShutDown[] = TEXT("Server ShutDown");
//如果服务器端接收到关闭消息接后,测试对话框是否关闭
HWND g_hMainDlg;
//服务器端线程
DWORD WINAPI ServerThread(PVOID pvParam)
{
//假定服务器端一直运行
BOOL fShutdown = FALSE;
while (!fShutdown)
{
//等待客户端提交请求
WaitForSingleObject(g_heveRequestedSubmitted, INFINITE);
//判断是否客户端要求服务器端关闭
fShutdown = (NULL == g_hMainDlg) &&
(_tcscmp(g_szSharedRequestAndResultBuffer, g_szServerShutDown) == 0);
//处理客户端请求(反转字符串)
if (!fShutdown)
{
_tcsrev(g_szSharedRequestAndResultBuffer);
}
//让客户端处理请求
SetEvent(g_hevtResultReturned);
}
//客户端要求服务器端关闭
return 0;
}
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
chSETDLGICONS(hwnd, IDI_HANDSHAKE);
//初始化对话框
Edit_SetText(GetDlgItem(hwnd, IDC_REQUEST), TEXT("Some test data"));
//保存主对话框句柄
g_hMainDlg = hwnd;
return TRUE;
}
void Dlg_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch (id)
{
case IDCANCEL:
EndDialog(hWnd, id);
break;
//提交消息到服务器端
case IDC_SUBMIT:
//拷贝请求字符串到共享缓存
Edit_GetText(GetDlgItem(hWnd, IDC_REQUEST), g_szSharedRequestAndResultBuffer, _countof(g_szSharedRequestAndResultBuffer));
//让服务器线程知道客户端请求事件
SetEvent(g_heveRequestedSubmitted);
//等待服务器处理,返回服务器给个结果
WaitForSingleObject(g_hevtResultReturned, INFINITE);
//将结果放入编辑框
Edit_SetText(GetDlgItem(hWnd, IDC_RESULT), g_szSharedRequestAndResultBuffer);
break;
default:
break;
}
}
INT_PTR WINAPI Dlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
{
chHANDLE_DLGMSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hWnd, WM_COMMAND, Dlg_OnCommand);
}
return (FALSE);
}
int WINAPI _tWinMain(HINSTANCE hInstanceExe, HINSTANCE, PTSTR, int)
{
//创建和初始化2个未重置,自动重置事件
g_heveRequestedSubmitted = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hevtResultReturned = CreateEvent(NULL, FALSE, FALSE, NULL);
//服务器端线程
DWORD dwThreadID;
HANDLE hThreadServer = chBEGINTHREADEX(NULL, 0, ServerThread, NULL, 0, &dwThreadID);
//客户端线程
DialogBox(hInstanceExe, MAKEINTRESOURCE(IDD_HANDSHAKE), NULL, Dlg_Proc);
g_hMainDlg = NULL;
_tcscpy_s(g_szSharedRequestAndResultBuffer, _countof(g_szSharedRequestAndResultBuffer), g_szServerShutDown);
SetEvent(g_heveRequestedSubmitted);
//等待服务器端获取关闭线程和等待服务器端完全销毁
HANDLE h[2];
h[0] = g_hevtResultReturned;
h[1] = hThreadServer;
WaitForMultipleObjects(2, h, TRUE, INFINITE);
CloseHandle(hThreadServer);
CloseHandle(g_heveRequestedSubmitted);
CloseHandle(g_hevtResultReturned);
return 0;
}