280 likes | 499 Views
Chap11 多线程编程. 本章大纲. 进程和线程基础知识 CWinThread 线程的创建和启动 线程的终止 线程间的通讯和同步 MTRECALC 例程序分析 MTGDI 例程序分析 MUTEXES 例程序分析. 进程和线程基础知识. 什么是进程 什么是线程 进程和线程的关系 进程和线程的优先级 辅助线程和用户界面线程. 进程是指在系统中正在运行的一个应用程序。. 什么是进程?. 进程用有它自己的内存、文件句柄及其他系统资源。. 进程具有自己私有的 4GB 虚拟地址空间。. 线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。.
E N D
本章大纲 • 进程和线程基础知识 • CWinThread • 线程的创建和启动 • 线程的终止 • 线程间的通讯和同步 • MTRECALC例程序分析 • MTGDI 例程序分析 • MUTEXES 例程序分析
进程和线程基础知识 • 什么是进程 • 什么是线程 • 进程和线程的关系 • 进程和线程的优先级 • 辅助线程和用户界面线程
进程是指在系统中正在运行的一个应用程序。 • 什么是进程? 进程用有它自己的内存、文件句柄及其他系统资源。 进程具有自己私有的4GB虚拟地址空间。
线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。 • 什么是线程? 每个线程有自己的栈和一份CPU寄存器的拷贝。 • 进程和线程的关系? 一个进程至少包括一个主线程,可以有多个子线程。 每个进程的所有线程共享同一个地址空间。
高优先级线程优先运行,优先级相同的线程按照时间片轮流运行高优先级线程优先运行,优先级相同的线程按照时间片轮流运行 • 进程和线程的优先级 线程的调度优先级:0~31级 0~15 级是普通优先级 只有系统线程可以设置0优先级 16~31级是实时优先级 优先级相同的线程不是按照时间片轮流运行,而是先运行的线程控制CPU。
线程的调度优先级=进程类基本优先级+线程相对优先级线程的调度优先级=进程类基本优先级+线程相对优先级 HIGH_PRIORITY_CLASS IDLE_PRIORITY_CLASS NORMAL_PRIORITY_CLASS REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_IDLE THREAD_PRIORITY_LOWEST THREAD_PRIORITY_NORMAL THREAD_PRIORITY_TIME_CRITICAL
(Worker Threads ) (User-Interface Threads ) • 辅助线程和用户界面线程 提供消息机制。 用来处理用户输入,响应事件和消息。 用来执行后台任务如:复杂计算、后台打印。 没有消息机制。
CWinThread类 • 是所有线程类的基类。 • 派生类CWinApp用于创建主线程 • CWinThread类题供了辅助线程和用户界面线程的支持。 • 创建线程 • CWinThread::CreateThread • 启动线程:DWORD ResumeThread( ); • 挂起线程:SuspendThread( ); • 设置优先级:SetThreadPriority( int nPriority ); • 重载函数
线程的创建和启动 指向辅助线程的控制函数。 UINT MyControllingFunction( LPVOID pParam ) • 创建辅助线程 CWinThread*AfxBeginThread (AFX_THREADPROCpfnThreadProc, LPVOIDpParam, intnPriority=THREAD_PRIORITY_NORMAL, UINTnStackSize=0, DWORDdwCreateFlags=0, LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL); 传给控制函数的参数 • CREATE_SUSPENDED挂起线程 • 0 --启动线程
线程的创建和启动 • 创建用户界面线程 1.CWinThread*AfxBeginThread ( CRuntimeClass*pThreadClass, intnPriority=HREAD_PRIORITY_NORMAL, UINTnStackSize=0, DWORDdwCreateFlags= 0, LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL); 2. CWinThread::CreateThread
线程的终止 • Normal Thread Termination • 辅助线程: 退出控制函数,并返回整型值. 正常退出返回0。 • 用户界面线程: 在线程内调用 ::PostQuitMessage函数. • Premature Thread Termination 调用AfxEndThread 函数. • Retrieving the Exit Code of a Thread BOOL GetExitCodeThread ( HANDLE hThread, // handle to the thread LPDWORD lpExitCode // address to receive termination status ); • STILL_ACTIVE线程在活动状态 • exit code --线程终止
线程间的通讯和同步 • 使用全局变量进行线程间通讯 • 把全局变量声明为Volatile,确保该变量不存储在寄存器中。 • 使用同步机制 • 同步对象:CSyncObject, CSemaphore, CMutex, CCriticalSection, 和 CEvent • 同步访问对象:CMultiLock和CSingleLock
事件和CEvent 允许一个线程通知另一个线程发生了某个事件 CEvent( BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL ) BOOL SetEvent( ) 设置有信号状态 BOOL ResetEvent( )设置无信号状态
事件同步 使用CEvent类创建全局事件对象,“启动”事件和“终止”事件。 主线程设定事件信号状态: • 调用CEnvent::SetEnvent函数设定事件为有信号状态。 辅助线程监视事件 • 使用CSingleLock类 • 使用Win32 WaitForSingleObject函数
DWORD WaitForSingleObject ( HANDLE hHandle, // handle to object to wait for DWORD dwMilliseconds // time-out interval in milliseconds ); • INFINITE- 直到hHandle对象成为有信号状态才返回 。 • 0-立即返回。 返回值: WAIT_ABANDONED:互斥信号量处于无信号状态。 WAIT_OBJECT_0 : hHandle对象处在有信号状态。 WAIT_TIMEOUT :等待时间超时,hHandle对象处在无信号状态。
临界区和CCriticalSection • 临界区只供单个进程的线程使用,可保证在任何时候只有一个线程访问某项资源。 • CCriticalSection封装了临界区对象 • CCriticalSection(); • virtual BOOL Unlock( ); • BOOL Lock( );
互斥量和CMutex类 • 与临界区的作用相似,允许在任意时刻有且仅有一个线程访问某资源。 • 有应用程序需要用同一个资源时,使用互斥量。只有一个进程需要用一个资源时,使用临界区。 • CMutex(BOOLbInitiallyOwn = FALSE,LPCTSTR lpszName = NULL,LPSECURITY_ATTRIBUTESlpsaAttribute = 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 string m_pOwner->m_strNumber.MakeReverse(); sLock.Unlock(); …. }