Chap11 多线程编程

28
Chap11 多多多多多

description

Chap11 多线程编程. 本章大纲. 进程和线程基础知识 CWinThread 线程的创建和启动 线程的终止 线程间的通讯和同步 MTRECALC 例程序分析 MTGDI 例程序分析 MUTEXES 例程序分析. 进程和线程基础知识. 什么是进程 什么是线程 进程和线程的关系 进程和线程的优先级 辅助线程和用户界面线程. 进程是指在系统中正在运行的一个应用程序。. 什么是进程?. 进程用有它自己的内存、文件句柄及其他系统资源。. 进程具有自己私有的 4GB 虚拟地址空间。. 线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。. - PowerPoint PPT Presentation

Transcript of Chap11 多线程编程

Page 1: Chap11  多线程编程

Chap11 多线程编程

Page 2: Chap11  多线程编程

本章大纲• 进程和线程基础知识• CWinThread• 线程的创建和启动• 线程的终止• 线程间的通讯和同步• MTRECALC 例程序分析• MTGDI 例程序分析• MUTEXES 例程序分析

Page 3: Chap11  多线程编程

进程和线程基础知识• 什么是进程• 什么是线程• 进程和线程的关系• 进程和线程的优先级• 辅助线程和用户界面线程

Page 4: Chap11  多线程编程

• 什么是进程?进程是指在系统中正在运行的一个应用程序。

进程用有它自己的内存、文件句柄及其他系统资源。

进程具有自己私有的 4GB虚拟地址空间。

Page 5: Chap11  多线程编程

• 什么是线程?线程是操作系统分配处理时间的基本单元。它代表一个独立的执行路径。

每个线程有自己的栈和一份CPU 寄存器的拷贝。

每个进程的所有线程共享同一个地址空间。

• 进程和线程的关系?

一个进程至少包括一个主线程,可以有多个子线程。

Page 6: Chap11  多线程编程

• 进程和线程的优先级

线程的调度优先级: 0~31 级0~15 级是普通优先级只有系统线程可以设置 0 优先

16~31 级是实时优先级

高优先级线程优先运行,优先级相同的线程按照时间片轮流运行

优先级相同的线程不是按照时间片轮流运行,而是先运行的线程控制 CPU 。

Page 7: Chap11  多线程编程

线程的调度优先级 = 进程类基本优先级 + 线程相对优先级

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

Page 8: Chap11  多线程编程

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

Page 9: Chap11  多线程编程

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

Page 10: Chap11  多线程编程

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

Page 11: Chap11  多线程编程

• 辅助线程和用户界面线程

用来执行后台任务如:复杂计算、后台打印。 没有消息机制。

提供消息机制。 用来处理用户输入,响应事件和消息。

( Worker Threads )( User-Interface Threads )

Page 12: Chap11  多线程编程

CWinThread 类• 是所有线程类的基类。• 派生类 CWinApp 用于创建主线程• CWinThread 类题供了辅助线程和用户界面线程的

支持。• 创建线程

– CWinThread::CreateThread

• 启动线程: DWORD ResumeThread( );• 挂起线程: SuspendThread( ); • 设置优先级: SetThreadPriority( int nPriority ); • 重载函数

Page 13: Chap11  多线程编程

函数名 用途ExitInstance 经常重载,用于在线程终止时作清理工作 .

InitInstance 必须重载,用于做线程的初始化。

OnIdle 不经常重载,用于在线程空闲时处理一些不太重要但较费时的任务。

PreTranslateMessage 不经常重载,用于过滤发送给 TranslateMessage 和 DispatchMessage 的消息。

ProcessWndProcException 不经常重载, 用于截取未处理的异常。

Run 很少重载,用于控制线程具有消息机制的线程。

• 可重载函数

Page 14: Chap11  多线程编程

线程的创建和启动创建辅助线程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  -- 启动线程

Page 15: Chap11  多线程编程

线程的创建和启动创建用户界面线程 1.CWinThread* AfxBeginThread

( CRuntimeClass* pThreadClass,

int nPriority = HREAD_PRIORITY_NORMAL,

UINT nStackSize = 0,

DWORD dwCreateFlags = 0,

LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

2. CWinThread::CreateThread

Page 16: Chap11  多线程编程

线程的终止 • 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   -- 线程终止

Page 17: Chap11  多线程编程

线程间的通讯和同步• 使用全局变量进行线程间通讯

– 把全局变量声明为 Volatile ,确保该变量不存储在寄存器中。

• 使用同步机制– 同步对象: CSyncObject, CSemaphore, CMut

ex, CCriticalSection, 和 CEvent– 同步访问对象: CMultiLock 和 CSingleLock

Page 18: Chap11  多线程编程

允许一个线程通知另一个线程发生了某个事件CEvent( BOOL bInitiallyOwn = FALSE,

BOOL bManualReset = FALSE,

LPCTSTR lpszName = NULL,

LPSECURITY_ATTRIBUTES lpsaAttribute = NULL )

BOOL SetEvent( ) 设置有信号状态

BOOL ResetEvent( ) 设置无信号状态

事件和 CEvent

Page 19: Chap11  多线程编程

事件同步使用 CEvent 类创建全局事件对象,“启动”

事件和“终止”事件。主线程设定事件信号状态:– 调用 CEnvent::SetEnvent 函数设定事件为有

信号状态。辅助线程监视事件– 使用 CSingleLock 类– 使用 Win32 WaitForSingleObject 函数

Page 20: Chap11  多线程编程

• 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- 立即返回。

Page 21: Chap11  多线程编程

临界区和 CCriticalSection

• 临界区只供单个进程的线程使用,可保证在任何时候只有一个线程访问某项资源。

• CCriticalSection 封装了临界区对象– CCriticalSection( ); – virtual BOOL Unlock( );– BOOL Lock( );

Page 22: Chap11  多线程编程

互斥量和 CMutex 类• 与临界区的作用相似,允许在任意时刻

有且仅有一个线程访问某资源。• 有应用程序需要用同一个资源时,使用

互斥量。只有一个进程需要用一个资源时,使用临界区。

• CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

Page 23: Chap11  多线程编程

信号量和 CSemaphore 类• 信号量对象允许有限数量的线程存取某个共享

的资源,采用计数器来实现信号量。• CSemaphore 类对象代表一个信号量对象。它维护着在访问指定资源的线程个数。

• CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );

Page 24: Chap11  多线程编程

访问同步对象• 信号量、事件、互斥量等同步对象的访问和控制

需要通过 CSingleLock 或 CMultiLock 对象来实现。

• 当在某一时刻只需要访问一个同步对象时,使用CSingleLock 类。– CSingleLock( CSyncObject* pObject, BOOL bInitialLock = FALSE );

• 当在某一时刻需要访问多个同步对象时,使用 CMultiLock 类。– CMultiLock( CSyncObject* ppObjects[ ], DWORD dwCount, BOOL bInitialLock = FALSE );

Page 25: Chap11  多线程编程

CSingleLock 和 CMultiLock 的成员函数

• IsLocked 判断同步对象是否被锁定• Lock 等待一个同步对象• Unlock 释放一个同步对象

Page 26: Chap11  多线程编程

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();…}

Page 27: Chap11  多线程编程

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();

Page 28: Chap11  多线程编程

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(); ….}