日期:2014-05-17  浏览次数:20820 次

Windows上多线程同步相关的MFC类
转载请标明出处:http://blog.csdn.net/zhangxingping

Windows上多线程同步相关的MFC类

相关类

MFC中提供的用于多线程程序中进行线程同步的类可以分为两类:同步类和同步访问类。

同步类

synchronization class

用于确保对资源完整性访问进行控制的类

CSyncObject

CSemaphore,

CMutex

CCriticalSection,

CEvent

同步访问类

Synchronization access class

用于获取受控资源访问权限的类

CMultiLock

CSingleLock

 

上面表格中的CSyncObject类为纯虚类,在实际中几乎不会直接使用它。它也是其它同步类的直接父类。

 

那么,在实际中应该如何判断到底需要使用上面的那个同步类了?一般遵循一下的原则:

1.        如果线程对资源的访问必须是在某个事件发生之后,那么可以使用CEvent。

2.        如果同一个程序中的多个线程可以在同一时刻访问资源,那么可以使用CSemaphore。

3.        如果多个程序可以访问资源,则可以使用CMutex;否则,使用CCriticalSection。

程序示例

CEvent

CEvent在线程必须等待某个事件发生后才能继续执行的情况下非常有用。它有两种工作模式:手动和自动。对于手动模式来说,事件的状态会一直保持到下一次调用SetEvent 或者 ResetEvent 对于自动模式来说,事件的状态会在唤醒至少一个线程之后重新恢复到不可用的状态。

 

下面的代码演示了CEvent的典型用法。程序中通过两个线程来分别输出20个a和b字符,但是我们期待这两个字符的输出是相间的,也就是不要出现连续的a或者连续的b。

Visual Studio创建的控制台程序,支持MFC:

// CEventDemo.cpp :定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
#include "CEventDemo.h"
 
#include "afxmt.h"
 
#include <conio.h>
 
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
 
// 唯一的应用程序对象
 
CWinApp theApp;
 
using namespacestd;
 
CEvent TrigerB(false);//用来唤醒线程B,来输出字符b
CEvent TrigerA(true);//用来唤醒线程A,来输出字符a
 
//线程A:用来输出字符a
UINT __cdecl ThreadA( LPVOIDpParam )
{
    for( int count = 0; count < 20; count++)
    {
        WaitForSingleObject(TrigerA.m_hObject,INFINITE);//等待被唤醒
        cout<< " a " ;
        TrigerA.ResetEvent();//重置,防止该线程输出连续的a
        //TrigerA.PulseEvent();
        TrigerB.SetEvent();//唤醒线程B
    }
 
    return 0;
 
}
 
//线程B:用来输出字符b
UINT __cdecl ThreadB( LPVOIDpParam )
{
 
    for( int count = 0; count < 20; count++)
    {
        WaitForSingleObject(TrigerB.m_hObject,INFINITE);//等待被唤醒
        cout<< " b " ;
        TrigerB.ResetEvent();//重置,防止该线程输出连续的b
        //TrigerB.PulseEvent();
        TrigerA.SetEvent();//唤醒线程A
    }
 
    return 0;
}
 
int _tmain(intargc,TCHAR*argv[],TCHAR*envp[])
{
    int nRetCode = 0;
 
    // 初始化MFC并在失败时显示错误
    if (!AfxWinInit(::GetModuleHandle(NULL),NULL, ::GetCommandLine(), 0))
    {
        // TODO: 更改错误代码以符合您的需要
        _tprintf(_T("错误: MFC初始化失败\n"));
        nRetCode= 1;
    }
    else
    {
        // TODO: 在此处为应用程序的行为编写代码。
 
        CWinThread* threadA = AfxBeginThread(ThreadB,NULL);
        CWinThread* threadB = AfxBeginThread(ThreadA,NULL);
 
        WaitForSingleObject(threadB->m_hThread,INFINITE);
        WaitForSingleObject(threadA->m_hThread,INFINITE);
 
        char c = getch();
    }
 
    return nRetCode;
}

CCriticalSection

CCriticalSection主要用于资源在同一个时刻只允许一个线程访问的情况;也就是主要用于临界区对临界资源的访问。

 

示例程序如下,Visual Studio创建的控制台程序,支持MFC: