chap11 多线程编程

28
Chap11 多多多多多

Upload: keefe

Post on 24-Jan-2016

104 views

Category:

Documents


0 download

DESCRIPTION

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

TRANSCRIPT

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