32位Windows没有每个应用程序只有一个线程的限制。
MFC在CWinThread类中封装了可执行线程,在C++类中封装了事件,互斥和其他Win32线程同步对象。
MFC把线程分为两个类型:UI线程和工作者线程。不同之处在于UI线程具有消息循环而工作者线程没有。
MFC中创建线程最好的方法是调用AfxBeginThread,有两个版本分别对应UI线程和工作者线程。只有在不使用MFC时才可以使用Win32::CreateThread()来创建线程。
创建工作者线程:
CWinThread* pThread = AfxBeginThread(ThreadFunc, &threadInfo);
需要传入一个线程函数和一个包含对线程输入的数据结构的地址。另外还有一个接受4个参数的原型,可以指定线程优先级、堆栈尺寸、产生标志以及安全属性。
创建UI线程:
UI线程是的行为是由从CWinThread派生来的可动态创建的类控制的,类似于CWinApp派生的应用程序。
CWinThread* pThread = AfxBeginThread(RUNTIME_CLASS(CUIThread));
暂停和继续执行线程:
CWinThread::SuspendThread()
CWinThread::REsumeThread()
线程睡眠:
::Sleep(time):在time时间后某时刻醒来。
::Sleep(0): 放弃剩余的时间片
终止线程:
DWORD dwExitCode;
::GetExitCodeThread(pThread->m_hThread, &dwExitCode);
线程同步:
- 临界区
串行化多个线程共享的链表,简单变量,结构等资源。
CCriticalSection g_cs; //Global data .... //Thread A g_cs.Lock(); .... g_cs.Unlock(); //Thread b g_cs.Lock(); .... g_cs.Unlock();
Lock()可以接受超时值。
- 互斥量
可以同步在不同进程上运行的线程。
//Global data CMutex g_mutex(FALSE, _T("MyMutex")); .... if(g_mutex(60000)) { ..... g_mutex.Unlock(); }
互斥量与临界区还有一个区别,如果线程锁定了临界区而终止时没有解锁,那么等待临界区空闲的其他线程将无限期阻塞下去。然而,如果锁定互斥量的线程不能在其终止前解除互斥量的锁定,那么系统将认为互斥量被放弃了并自动释放。
- 事件
一个事件对象不只是操作系统内核中的一个标记,在任何特定时间,时间只能处在两种状态中的一种:引发或者调低。
CEvent::SetEvent(); 设置一个事件
CEvent::ResetEvent(); 重置一个事件
CEvent::PulseEvent(); 设置或重置一个事件
如果事件只触发一个线程,自动重置SetEvent
如果时间触发多个线程,手动重置PulseEvent
CEvent g_event; ... //Thread A InitBuffer(&buffer); g_event.SetEvent(); //THread B g_event.Lock();
CEvent g_event(FALSE, TRUE); //Thread A InitBuffer(&buffer); g_event.PulseEvent(); //Thread B g_event.Lock(); //Thread C g_event.Lock();
- 信号量
始终保存代表可用资源数量的资源数。
CSemaphore g_semaphore(m, n); .... g_semaphore.Lock(); .... g_semaphore.Unlock();