您的位置:首页 > 其它

进程与线程(五)用内核对象进行线程同步(上)

2012-05-10 14:59 337 查看
当系统初始化一个内核对象时,会将其结构内部的一个变量初始化为FALSE,也就是未触发状态。线程可以等待一个内核对象,进入等待状态,当这个内核对象变为TURE的触发状态时,唤醒线程。

线程内核对象在线程初始化时设置为未触发,当线程结束时设置为触发,所以我们可以用WaitForSingleObject来等待一个线程的结束,CreateEvent可以创建一个事件内核对象,可以用来进行同步。

1 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
2 {
3     _tsetlocale(LC_ALL,_T("chs") );
4     system("title ReturnsMe的win32api测试程序");
5     //创建一个事件内核对象
6     g_hevent = CreateEvent(NULL,FALSE,FALSE,_T("event"));
7
8     chBEGINTHREADEX(NULL,NULL,PrintThread,NULL,0,NULL);
9     HANDLE h = chBEGINTHREADEX(NULL,NULL,SetThread,NULL,0,NULL);
10
11     WaitForSingleObject(h,INFINITE);
12
13     system("pause");
14     return 0;
15 }
16 DWORD WINAPI SetThread(PVOID pvParam)
17 {
18     for (int i =0;i<=100;i++)
19     {
20         g_num = g_num +i;
21     }
22     wprintf(_T("SetThread:g_num is %d \n"),g_num);
23     Sleep(2000);
24     SetEvent(g_hevent);  //设置内核对象为触发状态
25     return 0;
26 }
27
28 DWORD WINAPI PrintThread(PVOID pvParam)
29 {
30     WaitForSingleObject(g_hevent,INFINITE);
31     wprintf(_T("PrintThread:g_num is %d \n"),g_num);
32     return 0;
33 }
除了事件内核对象以外,还有计时器,信号量,互斥量等等内核对象可以用来线程同步,未完待续....

update:
计时器允许我们在特定时间触发一个内核对象,并且可以每隔一段时间触发一次。下面是一个例子,注释很详细。

1 HANDLE g_htimer;
2
3 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
4 {
5     _tsetlocale(LC_ALL,_T("chs") );
6     system("title ReturnsMe的win32api测试程序");
7
8     //设置一个手动重置的内核对象,如果我们没有从外部调用这个计时器的需求,我们可以给名字传一个NULL
9     g_htimer  = CreateWaitableTimer(NULL,FALSE,NULL);
10
11     FILETIME ftLocal,ftUTC,ftNewUTC;
12     SYSTEMTIME st;
13
14     //得到当前UTC时间,FILETIME格式
15     ftUTC = CFileTime::GetCurrentTime();
16     //时区换算
17     FileTimeToLocalFileTime(&ftUTC,&ftLocal);
18     //转换成系统时间
19     FileTimeToSystemTime(&ftLocal,&st);
20
21     wprintf(_T("time is %d:%d:%d \n" ),st.wHour,st.wMinute,st.wSecond);
22
23     //即时时间加两秒,然后转换成FILETIME格式的UTC时间
24     st.wSecond = st.wSecond +2;
25
26     SystemTimeToFileTime(&st,&ftLocal);
27     LocalFileTimeToFileTime(&ftLocal,&ftNewUTC);
28
29     //这么做是为了兼容x64cpu,对齐地址
30     LARGE_INTEGER li;
31     li.HighPart = ftNewUTC.dwHighDateTime;
32     li.LowPart = ftNewUTC.dwLowDateTime;
33
34     //设置计时器,第二个参数传入绝对时间,也就是刚才得到的CFileTime::GetCurrentTime();的2s后
35     //第一次设置计时器为触发状态,以后每5s触发一次
36     SetWaitableTimer(g_htimer,&li,5000,NULL,NULL,FALSE);
37     HANDLE h = chBEGINTHREADEX(NULL,NULL,PrintThread,NULL,0,NULL);
38
39     WaitForSingleObject(h,1000*60);
40
41     system("pause");
42     return 0;
43 }
44 DWORD WINAPI PrintThread(PVOID pvParam)
45 {
46
47     for (int i=0;i<=5;i++)
48     {
49         //循环等待,打印6次后退出线程
50         WaitForSingleObject(g_htimer,INFINITE);
51         wprintf(_T("this is the %dth time to call wprintf \n"),i+1);
52     }
53
54     //用完了就做掉它,=。=|||
55     CancelWaitableTimer(g_htimer);
56
57     return 0;
58 }
59
当然set函数也可以设置一个相对时间,而且也允许插入一个时间的apc
HANDLE g_htimer;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
_tsetlocale(LC_ALL,_T("chs") );
system("title ReturnsMe的win32api测试程序");

AccessTimerAndAPC();

system("pause");
return 0;
}

VOID AccessTimerAndAPC()
{
g_htimer = CreateWaitableTimer(NULL,TRUE,NULL);

FILETIME ftUTC,ftLocal;
SYSTEMTIME st;
ftUTC = CFileTime::GetCurrentTime();

FileTimeToLocalFileTime(&ftUTC,&ftLocal);
FileTimeToSystemTime(&ftLocal,&st);

//上次是绝对时间,这次用相对时间,传给apc一个创建时间
LARGE_INTEGER li={0};
SetWaitableTimer(g_htimer,&li,1000,APCRoutine,(LPVOID)&st,FALSE);

//当且仅当函数处于一个alertable state时,系统才会把计时器的APC函数添加到列队之中
SleepEx(INFINITE,TRUE);

}
VOID WINAPI APCRoutine(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue)
{
PSYSTEMTIME pst = (PSYSTEMTIME)lpArgToCompletionRoutine;
wprintf(_T("apc is inserted to the routine at %d:%d:%d \n"),pst->wHour,pst->wMinute,pst->wSecond);

Sleep(2000);
FILETIME ftUTC,ftLocal;
ftUTC = CFileTime::GetCurrentTime();

FileTimeToLocalFileTime(&ftUTC,&ftLocal);
FileTimeToSystemTime(&ftLocal,pst);

wprintf(_T("it's  %d:%d:%d  now \n"),pst->wHour,pst->wMinute,pst->wSecond);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐