VC++线程同步解析
2012-08-10 14:21:29 来源:WEB开发网核心提示:图2 CEvent 类对线程的同步过程示意B 线程在执行到CEvent 类成员函数Lock()时将会发生阻塞,而A 线程此时则可以在没有B 线程干扰的情况下对共享资源进行处理,VC++线程同步解析(5),并在处理完成后通过成员函数SetEvent()向B发出事件,使其被释放,使用信号量内核对象进行线程同步主要会用到Cr
图2 CEvent 类对线程的同步过程示意
B 线程在执行到CEvent 类成员函数Lock()时将会发生阻塞,而A 线程此时则可以在没
有B 线程干扰的情况下对共享资源进行处理,并在处理完成后通过成员函数SetEvent()向B
发出事件,使其被释放,得以对A 先前已处理完毕的共享资源进行操作。可见,使用CEvent
类对线程的同步方法与通过API 函数进行线程同步的处理方法是基本一致的。前面的API 处理
代码可用CEvent 类将其改写为:
// MFC 事件类对象
CEvent g_clsEvent;
UINT ThreadProc22(LPVOID pParam)
{
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[i] = 'a';
Sleep(1);
}
// 事件置位
g_clsEvent.SetEvent();
return 0;
}
UINT ThreadProc23(LPVOID pParam)
{
// 等待事件
g_clsEvent.Lock();
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[10 - i - 1] = 'b';
Sleep(1);
}
return 0;
}
……
void CSample08View::OnEventMfc()
{
// 启动线程
AfxBeginThread(ThreadProc22, NULL);
AfxBeginThread(ThreadProc23, NULL);
// 等待计算完毕
Sleep(300);
// 报告计算结果
CString sResult = CString(g_cArray);
AfxMessageBox(sResult);
}
信号量内核对象
信号量(Semaphore)内核对象对线程的同步方式与前面几种方法不同,它允许多个线程
在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用
CreateSemaphore()创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。
一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用
资源计数就会减1,只要当前可用资源计数是大于0 的,就可以发出信号量信号。但是当前可用
计数减小到0 时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他
线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过
ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可
能大于最大资源计数。
图3 使用信号量对象控制资源
下面结合图例3 来演示信号量对象对资源的控制。在图3 中,以箭头和白色箭头表示共享
资源所允许的最大资源计数和当前可用资源计数。初始如图(a)所示,最大资源计数和当前可
用资源计数均为4,此后每增加一个对资源进行访问的线程(用黑色箭头表示)当前资源计数就
会相应减1,图(b)即表示的在3 个线程对共享资源进行访问时的状态。当进入线程数达到4
个时,将如图(c)所示,此时已达到最大资源计数,而当前可用资源计数也已减到0,其他线
程无法对共享资源进行访问。在当前占有资源的线程处理完毕而退出后,将会释放出空间,图(d)
已有两个线程退出对资源的占有,当前可用计数为2,可以再允许2 个线程进入到对资源的处理。
可以看出,信号量是通过计数来对线程访问资源进行控制的,而实际上信号量确实也被称作
Dijkstra 计数器。
使用信号量内核对象进行线程同步主要会用到CreateSemaphore()、OpenSemaphore
()、ReleaseSemaphore()、WaitForSingleObject()和WaitForMultipleObjects()
等函数。其中,CreateSemaphore()用来创建一个信号量内核对象,其函数原型为:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性指针
B 线程在执行到CEvent 类成员函数Lock()时将会发生阻塞,而A 线程此时则可以在没
有B 线程干扰的情况下对共享资源进行处理,并在处理完成后通过成员函数SetEvent()向B
发出事件,使其被释放,得以对A 先前已处理完毕的共享资源进行操作。可见,使用CEvent
类对线程的同步方法与通过API 函数进行线程同步的处理方法是基本一致的。前面的API 处理
代码可用CEvent 类将其改写为:
// MFC 事件类对象
CEvent g_clsEvent;
UINT ThreadProc22(LPVOID pParam)
{
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[i] = 'a';
Sleep(1);
}
// 事件置位
g_clsEvent.SetEvent();
return 0;
}
UINT ThreadProc23(LPVOID pParam)
{
// 等待事件
g_clsEvent.Lock();
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[10 - i - 1] = 'b';
Sleep(1);
}
return 0;
}
……
void CSample08View::OnEventMfc()
{
// 启动线程
AfxBeginThread(ThreadProc22, NULL);
AfxBeginThread(ThreadProc23, NULL);
// 等待计算完毕
Sleep(300);
// 报告计算结果
CString sResult = CString(g_cArray);
AfxMessageBox(sResult);
}
信号量内核对象
信号量(Semaphore)内核对象对线程的同步方式与前面几种方法不同,它允许多个线程
在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用
CreateSemaphore()创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。
一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用
资源计数就会减1,只要当前可用资源计数是大于0 的,就可以发出信号量信号。但是当前可用
计数减小到0 时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他
线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过
ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可
能大于最大资源计数。
图3 使用信号量对象控制资源
下面结合图例3 来演示信号量对象对资源的控制。在图3 中,以箭头和白色箭头表示共享
资源所允许的最大资源计数和当前可用资源计数。初始如图(a)所示,最大资源计数和当前可
用资源计数均为4,此后每增加一个对资源进行访问的线程(用黑色箭头表示)当前资源计数就
会相应减1,图(b)即表示的在3 个线程对共享资源进行访问时的状态。当进入线程数达到4
个时,将如图(c)所示,此时已达到最大资源计数,而当前可用资源计数也已减到0,其他线
程无法对共享资源进行访问。在当前占有资源的线程处理完毕而退出后,将会释放出空间,图(d)
已有两个线程退出对资源的占有,当前可用计数为2,可以再允许2 个线程进入到对资源的处理。
可以看出,信号量是通过计数来对线程访问资源进行控制的,而实际上信号量确实也被称作
Dijkstra 计数器。
使用信号量内核对象进行线程同步主要会用到CreateSemaphore()、OpenSemaphore
()、ReleaseSemaphore()、WaitForSingleObject()和WaitForMultipleObjects()
等函数。其中,CreateSemaphore()用来创建一个信号量内核对象,其函数原型为:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性指针
更多精彩
赞助商链接