您的位置:首页 > 编程语言

<<windows核心编程>>读书笔记---第9章 内核对象进行线程同步

2013-08-28 16:37 375 查看
这是比较重要的一章,经常使用。应该牢靠掌握。

等待函数:

DWORD WINAPI WaitForSingleObject(
__in          HANDLE hHandle,
__in          DWORD dwMilliseconds
);


这个函数经常使用啦,当hHandle变为已触发状态的时候返回,不然就进入等待状态。

这里我们需要注意的是返回值,分为三种:WAIT_OBJECT_0(线程等待的对象被触发),WAIT_TIMEOUT(等待超时),WAIT_FAILED(参数传入了无效的句柄等)

当然如果是等待多个对象:

DWORD WINAPI WaitForMultipleObjects(
__in          DWORD nCount,
__in          const HANDLE* lpHandles,
__in          BOOL bWaitAll,
__in          DWORD dwMilliseconds
);


参数都是显而易见的,第一个参数为内核对象的数量,第二个参数是内核对象数组,第三个参数指定是否为全部,第四个是等待时间。
第三个参数如果为TRUE,则表示所有的内核对象都被触发了,函数才返回。反之,有一个被触发就返回。

这里的返回值需要特殊强调一下:如果bWaitAll为True,返回值为WAIT_OBJECT_0,则表示所有对象都被触发了。如果,bWaitAll为False,且返回值为WAIT_OBJECT_0和WAIT_OBJECT_0+nCount-1之间的某个值,则表示数组中第几个对象触发了。

信号量内核对象:

创建:

HANDLE WINAPI CreateSemaphore(
__in          LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
__in          LONG lInitialCount,
__in          LONG lMaximumCount,
__in          LPCTSTR lpName
);


第一个参数和最后一个参数依然是内核对象经常看到的结构,第二个参数是当前可使用的资源数,第三个参数是可使用资源的总量(最大量)。
其实用法还是很简单的,有时候我总是把它想的复杂,其实完全没必要。

声明一个信号量内核对象,在线程函数里,使用WaitForSingleObject()来等待信号量,如果当前的可使用资源数小于可使用资源的总量,那么等待函数就可以返回,从而执行后续步骤。当然,返回返回必然会导致可使用资源数的减少,调用ReleaseSemaphore来设置使用的资源数。当然这只是最基本的用法。

BOOL WINAPI ReleaseSemaphore(
__in          HANDLE hSemaphore,
__in          LONG lReleaseCount,
__out         LPLONG lpPreviousCount
);


最后一个参数代表的是会返回当前资源的原始值,如果我们将lReleaseCount传入0或者一个极大值,lpPreviousCount也会返回0。
网摘了一段代码,还是挺清晰的:

#include <windows.h>
#include <iostream>
#include <ctime>
#include <fstream>

using namespace std;

HANDLE hSemaphore;

struct ThreadInfo
{
int iID;
LONG iCount;
ThreadInfo* pThreadInfo;
int iSleep;
};

DWORD WINAPI ThreadProc(LPVOID lp)
{
ThreadInfo* pThreadInfo = (ThreadInfo*)lp;
WaitForSingleObject(hSemaphore,INFINITE);
Sleep(pThreadInfo->iSleep);
cout << "线程" << pThreadInfo->iID << ":睡眠" << pThreadInfo->iSleep << endl;

ReleaseSemaphore(hSemaphore,1,&(pThreadInfo->iCount));
cout << "线程" << pThreadInfo->iID << ":当前信号量资源数:" << pThreadInfo->iCount << "  信号量资源数加1" << endl;

delete pThreadInfo->pThreadInfo;
return 0;
}

int main(int argc, char *argv[])
{
cout << "信号量当前资源数:4,最大资源数:5" << endl;
hSemaphore = CreateSemaphore(NULL,4,5,NULL);
HANDLE hThread[8];
srand((unsigned)time(0));
for(int i = 0;i < 8;++i)
{
ThreadInfo* threadInfo = new ThreadInfo;
threadInfo->pThreadInfo = threadInfo;
threadInfo->iID = i;
threadInfo->iCount = -1;
threadInfo->iSleep = rand() % 1000;
hThread[i] = CreateThread(NULL,0,ThreadProc,(LPVOID)threadInfo,0,NULL);
}
WaitForMultipleObjects(8,hThread,TRUE,INFINITE);
for(int i = 0;i < 8;++i)
CloseHandle(hThread[i]);
CloseHandle(hSemaphore);
return 0;
}


互斥量内核对象:

互斥量其实和关键段差不多:



看这个表格,够言简意赅的。

互斥量和其他内核对象有点区别:如果线程请求其他内核对象,请求不到资源的话,会进入等待状态。但是,如果是线程请求互斥量,则先要检查互斥量锁归属的线程,如果是同一个线程,则将互斥量归属的线程计数+1,当然,如果不是同一个线程,则继续进入等待状态。

遗弃问题:

如果某个线程获得了互斥量,但是没有释放就线程结束了,系统会自动将互斥量的线程ID设置为0,并将其递归计数设置为0,然后系统会检查其他等待中的线程,公平的选择其中一个,将其变为可调度状态。注意WaitForSingleObject函数的返回值也会变为WAIT_ABANDONED。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: