chap11 多线程编程
DESCRIPTION
Chap11 多线程编程. 本章大纲. 进程和线程基础知识 CWinThread 线程的创建和启动 线程的终止 线程间的通讯和同步 MTRECALC 例程序分析 MTGDI 例程序分析 MUTEXES 例程序分析. 进程和线程基础知识. 什么是进程 什么是线程 进程和线程的关系 进程和线程的优先级 辅助线程和用户界面线程. 进程是指在系统中正在运行的一个应用程序。. 什么是进程?. 进程用有它自己的内存、文件句柄及其他系统资源。. 进程具有自己私有的 4GB 虚拟地址空间。. 线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。. - PowerPoint PPT PresentationTRANSCRIPT
Chap11 多线程编程
本章大纲• 进程和线程基础知识• CWinThread• 线程的创建和启动• 线程的终止• 线程间的通讯和同步• MTRECALC 例程序分析• MTGDI 例程序分析• MUTEXES 例程序分析
进程和线程基础知识• 什么是进程• 什么是线程• 进程和线程的关系• 进程和线程的优先级• 辅助线程和用户界面线程
• 什么是进程?进程是指在系统中正在运行的一个应用程序。
进程用有它自己的内存、文件句柄及其他系统资源。
进程具有自己私有的 4GB虚拟地址空间。
• 什么是线程?线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。
每个线程有自己的栈和一份CPU 寄存器的拷贝。
每个进程的所有线程共享同一个地址空间。
• 进程和线程的关系?
一个进程至少包括一个主线程,可以有多个子线程。
• 进程和线程的优先级
线程的调度优先级: 0~31 级0~15 级是普通优先级只有系统线程可以设置 0 优先
级
16~31 级是实时优先级
高优先级线程优先运行,优先级相同的线程按照时间片轮流运行
优先级相同的线程不是按照时间片轮流运行,而是先运行的线程控制 CPU 。
线程的调度优先级 = 进程类基本优先级 + 线程相对优先级
HIGH_PRIORITY_CLASSIDLE_PRIORITY_CLASS NORMAL_PRIORITY_CLASS REALTIME_PRIORITY_CLASS
THREAD_PRIORITY_ABOVE_NORMALTHREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_IDLE THREAD_PRIORITY_LOWEST THREAD_PRIORITY_NORMAL THREAD_PRIORITY_TIME_CRITICAL
Process Priority Class Thread Priority Level
1 IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS
THREAD_PRIORITY_IDLE
2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST
3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL
4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL
5 Background NORMAL_PRIORITY_CLASS
THREAD_PRIORITY_LOWEST
IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL
6 Background NORMAL_PRIORITY_CLASS
THREAD_PRIORITY_BELOW_NORMAL
Process Priority Class Thread Priority Level
7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST
Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL
8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL
NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL
9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL
NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST
10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL
11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST
Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST
12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL
Process Priority Class Thread Priority Level
13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL
14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL
15 IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS
THREAD_PRIORITY_TIME_CRITICAL
HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST
16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE
22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST
23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL
24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL
25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL
26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST
31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL
• 辅助线程和用户界面线程
用来执行后台任务如:复杂计算、后台打印。 没有消息机制。
提供消息机制。 用来处理用户输入,响应事件和消息。
( Worker Threads )( User-Interface Threads )
CWinThread 类• 是所有线程类的基类。• 派生类 CWinApp 用于创建主线程• CWinThread 类题供了辅助线程和用户界面线程的
支持。• 创建线程
– CWinThread::CreateThread
• 启动线程: DWORD ResumeThread( );• 挂起线程: SuspendThread( ); • 设置优先级: SetThreadPriority( int nPriority ); • 重载函数
函数名 用途ExitInstance 经常重载,用于在线程终止时作清理工作 .
InitInstance 必须重载,用于做线程的初始化。
OnIdle 不经常重载,用于在线程空闲时处理一些不太重要但较费时的任务。
PreTranslateMessage 不经常重载,用于过滤发送给 TranslateMessage 和 DispatchMessage 的消息。
ProcessWndProcException 不经常重载, 用于截取未处理的异常。
Run 很少重载,用于控制线程具有消息机制的线程。
• 可重载函数
线程的创建和启动创建辅助线程CWinThread* AfxBeginThread
( AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
指向辅助线程的控制函数。UINT MyControllingFunction( LPVOID pParam )
传给控制函数的参数
•CREATE_SUSPENDED 挂起线程• 0 -- 启动线程
线程的创建和启动创建用户界面线程 1.CWinThread* AfxBeginThread
( CRuntimeClass* pThreadClass,
int nPriority = HREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
2. CWinThread::CreateThread
线程的终止 • Normal Thread Termination
– 辅助线程: 退出控制函数,并返回整型值 . 正常退出返回 0 。– 用户界面线程 : 在线程内调用 ::PostQuitMessage 函数 .
• Premature Thread Termination 调用 AfxEndThread 函数 . • Retrieving the Exit Code of a ThreadBOOL GetExitCodeThread( HANDLE hThread, // handle to the thread LPDWORD lpExitCode // address to receive termination status );
•STILL_ACTIVE 线程在活动状态 • exit code -- 线程终止
线程间的通讯和同步• 使用全局变量进行线程间通讯
– 把全局变量声明为 Volatile ,确保该变量不存储在寄存器中。
• 使用同步机制– 同步对象: CSyncObject, CSemaphore, CMut
ex, CCriticalSection, 和 CEvent– 同步访问对象: CMultiLock 和 CSingleLock
允许一个线程通知另一个线程发生了某个事件CEvent( BOOL bInitiallyOwn = FALSE,
BOOL bManualReset = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL )
BOOL SetEvent( ) 设置有信号状态
BOOL ResetEvent( ) 设置无信号状态
事件和 CEvent
事件同步使用 CEvent 类创建全局事件对象,“启动”
事件和“终止”事件。主线程设定事件信号状态:– 调用 CEnvent::SetEnvent 函数设定事件为有
信号状态。辅助线程监视事件– 使用 CSingleLock 类– 使用 Win32 WaitForSingleObject 函数
• DWORD WaitForSingleObject
( HANDLE hHandle, // handle to object to wait for
DWORD dwMilliseconds // time-out interval in milliseconds );
返回值:
WAIT_ABANDONED :互斥信号量处于无信号状态。 WAIT_OBJECT_0 : hHandle 对象处在有信号状态。WAIT_TIMEOUT :等待时间超时, hHandle 对象处在无信号状态。
• INFINITE- 直到 hHandle 对象成为有信号状态才返回 。
• 0- 立即返回。
临界区和 CCriticalSection
• 临界区只供单个进程的线程使用,可保证在任何时候只有一个线程访问某项资源。
• CCriticalSection 封装了临界区对象– CCriticalSection( ); – virtual BOOL Unlock( );– BOOL Lock( );
互斥量和 CMutex 类• 与临界区的作用相似,允许在任意时刻
有且仅有一个线程访问某资源。• 有应用程序需要用同一个资源时,使用
互斥量。只有一个进程需要用一个资源时,使用临界区。
• CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );
信号量和 CSemaphore 类• 信号量对象允许有限数量的线程存取某个共享
的资源,采用计数器来实现信号量。• CSemaphore 类对象代表一个信号量对象。它维护着在访问指定资源的线程个数。
• CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );
访问同步对象• 信号量、事件、互斥量等同步对象的访问和控制
需要通过 CSingleLock 或 CMultiLock 对象来实现。
• 当在某一时刻只需要访问一个同步对象时,使用CSingleLock 类。– CSingleLock( CSyncObject* pObject, BOOL bInitialLock = FALSE );
• 当在某一时刻需要访问多个同步对象时,使用 CMultiLock 类。– CMultiLock( CSyncObject* ppObjects[ ], DWORD dwCount, BOOL bInitialLock = FALSE );
CSingleLock 和 CMultiLock 的成员函数
• IsLocked 判断同步对象是否被锁定• Lock 等待一个同步对象• Unlock 释放一个同步对象
MUTEXES 例程序分析CMutex m_mutex; // 创建对象int CDisplayThread::Run(){….
CSingleLock sLock(&(m_pOwner->m_mutex));
sLock.Lock();
// Construct a string with the string form of the number.
strBuffer = _T("Dspy: ");strBuffer += m_pOwner->m_strNumber;
sLock.Unlock();…}
MUTEXES 例程序分析int CCounterThread::Run()
{
CSingleLock sLock(&(m_pOwner->m_mutex));
sLock.Lock();
_stscanf((LPCTSTR) m_pOwner->m_strNumber, _T("%d"), &nNumber);
nNumber++;
m_pOwner->m_strNumber.Empty();
while (nNumber != 0){
m_pOwner->m_strNumber += (TCHAR) ('0' + nNumber%10);
// A call to Sleep() here tells the system that we want// to relinquis the remainder of our time slice to// another thread. Sleep(0);
// get ready to get the next digit.nNumber /= 10;
}
// Characters were generated in reverse order,// reverse the stringm_pOwner->m_strNumber.MakeReverse();
sLock.Unlock(); ….}