Windows 编程技术

19
1 Windows 编编编编 多多多

description

Windows 编程技术. 多任务. 概述. Windows 是一个抢先式多任务操作系统。所谓多任务是指它可以允许多个进程同时运行,而每个进程又由一个或多个线程组成,这些线程也可以同时运行,所谓抢先是指操作系统可以在任何时候挂起当前进程或线程的执行,把 CPU 控制权转交给别的进程或线程继续执行。 在操作系统中,一个进程通常就是一个运行着的程序,它可以由一个或多个模块组成,每个模块通常对应磁盘上的一个文件,如 EXE 或 DLL 文件。而一个线程通常就是这个程序中可以并行运行的某一个全局函数。本章将讲述进程和线程的使用方法。. 进程. 进程的优先级 - PowerPoint PPT Presentation

Transcript of Windows 编程技术

Page 1: Windows 编程技术

1

Windows 编程技术多任务

Page 2: Windows 编程技术

2

概述 Windows 是一个抢先式多任务操作系统。所谓多任务是指它可以允许多个进程同时运行,而每个进程又由一个或多个线程组成,这些线程也可以同时运行,所谓抢先是指操作系统可以在任何时候挂起当前进程或线程的执行,把 CPU 控制权转交给别的进程或线程继续执行。 在操作系统中,一个进程通常就是一个运行着的程序,它可以由一个或多个模块组成,每个模块通常对应磁盘上的一个文件,如 EXE 或 DLL 文件。而一个线程通常就是这个程序中可以并行运行的某一个全局函数。本章将讲述进程和线程的使用方法。

Page 3: Windows 编程技术

3

进程 进程的优先级

一个进程 (process) 是应用程序的一个运行实例,进程并不一定都有窗口或显示在屏幕上,每个进程都有自己的内存空间、代码、数据和系统资源。一个进程在运行的过程中创建的资源随着进程的终止而被销毁,分配的系统资源在进程终止时被释放或关闭。在 Windows 系统中,对每个进程可设置不同的优先级,

Windows 系统内部的调度程序根据进程的优先级来酌情分配 CPU 时间以使进程运行。一般情况下,进程优先级应被设置成标准级 NORMAL_PRIORITY_CLASS ,教材表 14-1 是 Windows定义的进程优先级类型。

Page 4: Windows 编程技术

4

进程 启动进程

CreateProcess()该函数是基本的启动进程函数,其函数原型定义如下:BOOL CreateProcess( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );

Page 5: Windows 编程技术

5

进程 CreateProcess 示例以下程序代码启动注册表程序:STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory( &si, sizeof(si) );si.cb = sizeof(si);ZeroMemory( &pi, sizeof(pi) );if(!CreateProcess(NULL,"regedit",NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) { AfxMessageBox( " 建立进程失败! " );}

Page 6: Windows 编程技术

6

进程 WinExec() 启动进程该函数内部调用 CreateProcess() 启动进程,其原型定义如下:UINT WinExec(LPCSTR lpCmdLine,UINT uCmdShow);参数 lpCmdLine 为命令行参数。参数 uCmdShow 为窗口的样式,该值用于 ShowWindow (HWND hwn

d, int nCmdShow) 中的 nCmdShow 来显示窗口,参见本书“ 1.3简单的 Windows 程序介绍”一节内容。以下程序代码启动注册表程序:if ( WinExec("regedit.exe",SW_SHOWNORMAL) ){ AfxMessageBox( " 建立进程失败! " );} C/C++ 语言中的启动进程函数启动进程

Page 7: Windows 编程技术

7

进程 进程的管理

取得当前进程的句柄及 ID GetCurrentProcess DuplicateHandle GetCurrentProcessID

取得其它进程的句柄及 ID CreateToolhelp32Snapshot Process32First Process32Next OpenProcess

Page 8: Windows 编程技术

8

进程 取得和设置进程的优先级

取得进程优先级, hProcess 为目标进程句柄:DWORD GetPriorityClass(HANDLE hProcess);

设置进程优先级, hProcess 为进程句柄: dwPriorityClass 为进程新的优先级:DWORD SetPriorityClass(HANDLE hProcess, DWORD dwPriorityCl

ass);

终止进程 在一进程任务完成后,可以调用函数 ExitProcess() 结束进程:

VOID ExitProcess(UINT uExitCode) 函数 TerminateProcess() 可以结束调用进程和其它进程:

BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode);

Page 9: Windows 编程技术

9

线程 线程的优先级

线程 (Thread) 是进程内部的一个可执行路径。例如,启动“记事本”程序时,操作系统将创建进程并开始执行进程的主线程 (primary thread) 。所有进程至少拥有一个线程,即主线程,主线程终止,进程终止。多个线程可以并发或并行的运行于同一个进程之中,每个线程都共享它们的进程的内存空间、全局变量和系统资源等。同进程一样,线程也有优先级。 Windows 定义了线程的优先级类型,合理使用这些优先级可以改善程序性能。例如,通常从调制解调器接收数据的线程比需要从磁盘文件读取数据的进程更高的优先级,因为从调制解调器接收数据的线程必须及时接收传来的数据,而磁盘文件上的数据一直都有。教材表

14-7 列举了线程优先级类型及其说明。

Page 10: Windows 编程技术

10

线程 线程的创建和终止

线程的创建 MFC 使用 AfxBeginThread() 函数在创建线程 Windows API 使用 CreateThread() 函数创建线程。 为线程函数,它的原型必须按照如下方式定义:

UINT ThreadProc(LPVOID pParam);

线程的终止 工作者线程,退出线程函数的同时即可正常终止线程 。 AfxEndThread() 、 ExitThread() 或者使用 return (即线程隐含调用了 ExitThread )来终止所在的线程。 TerminateThread() 终止线程。

Page 11: Windows 编程技术

11

线程 工作者线程

工作者线程不处理 Windows消息,通常比用户接口线程简单。 创建一个工作者线程。CWinThread* thread = AfxBeginThread(ThreadProcedure, pParam); 线程函数代码示例UINT WorkerThread(LPVOID pParam){

char* pMessage = (char *)pParam;AfxMessageBox(pMessage);return 0;

} 启动线程代码示例AfxBeginThread(WorkerThread, " 工作者线程运行 !");

Page 12: Windows 编程技术

12

线程 用户接口线程

用户接口线程含有消息循环,通常较工作者线程复杂。 从 CWinThread 类派生一个线程类, 重载 InitInstance() 函数,执行初始化任务。 重载 ExitInstance() 函数,清除自身。 代码示例:

添加 CWinThread 派生类 CMyThread 修改 CWinThread 类的 InitInstance() 函数 BOOL CMythread::InitInstance(){

CFrameWnd* pFrameWnd = new CFrameWnd();pFrameWnd->Create(NULL, “Thread Window”); // 创建线程窗口pFrameWnd->MoveWindow(0,0,150,150); …return TRUE;

} 启动线程AfxBeginThread(RUNTIME_CLASS(CMyThread));

Page 13: Windows 编程技术

13

进程、线程间的同步 概述

同步技术可以解决多个进程、线程在访问共享资源时发生冲突问题。 假设两个线程同时访问一个共享数据,甲线程进行数据修改,乙线程进行数据读取。由于 Windows 为抢先式多任务操作系统,当甲线程在数据修改到一半时,系统可能会挂起甲线程,让乙线程运行,乙线程将读到错误数据,导致程序运行出错。 为了避免冲突, Windows 系统内部定义了四个同步对象和一组等待函数,合理的使用它们可以解决多进程、多线程间的同步问题。 MFC 中 CEvent 类、 CCriticalSection 类、 CMutex 类和 CSemaphor

e 类封装了四个同步对象的操作,这 4 个类从一个纯虚基类 CSyncObject派生, CSyncObject 类包含两个重要函数 :

virtual BOOL Lock( DWORD dwTimeout = INFINITE );该函数判断同步对象是否可用,如果可用获得对象virtual BOOL Unlock() 该函数释放调用线程所拥有的同步对象,

Page 14: Windows 编程技术

14

进程、线程间的同步 等待函数

WaitForSingleObject该函数挂起当前线程,直到满足条件后才返回。它的原型定义如下:DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);参数 hHandle 是同步对象句柄,对象都被激活后返回WAIT_OBJECT_0;参数 dwMilliseconds 以毫秒为单位,如果为 0 ,那么函数就测试同步对象的状态并立即返回,如果为 INFINITE ,则超时间隔是无限的。 WaitForMultipleObjects 该函数挂起当前线程,直到满足条件后才返回。它的原型定义如下:DWORD WaitForMultipleObjects(DWORD nCount, CONST HANDLE *lpHandles , BOOL bWaitAll,DWORD dwMilliseconds ); 参数 nCount 是句柄数组中句柄的数目。 参数 lpHandles 代表一个句柄数组。参数 bWaitAll 说明了等待类型

Page 15: Windows 编程技术

15

进程、线程间的同步 使用事件 CEvent

MFC 的 CEvent 类封装事件的操作。通常当应用程序必须等到发生某事才能访问资源时,使用 CEvent 对象。 CCriticalSection CMutex CSemaphore

Page 16: Windows 编程技术

16

进程、线程间的同步 使用事件 CEvent

用法MFC 的 CEvent 类封装事件的操作。通常当应用程序必须等到发生某事才能访问资源时,使用 CEvent 对象。

状态活动 (signal state)沉寂 (nosignal state)

示例#include <afxmt.h> //包含头文件CEvent Event; // 建立沉寂的、自动的全局 CEvent 对象,用于线程同步CString csString; // 建立全局 CString 对象,用于存储字符串信息UINT Thread(LPVOID pParam) // 显示字符串信息的线程{while(1){Event.Lock(); // 或 WaitForSingleObject(Event,INFINITE);// 等待 Event 被激活,当函数返回后 Event 将自动设为沉寂AfxMessageBox(csString);}

}

Page 17: Windows 编程技术

17

进程、线程间的同步 使用临界段 CCriticalSection

用法CCriticalSection 类封装临界段的操作 。通常当一个应用程序的多个线程需要访问同一资源时,使用 CCriticalSection 对象。

状态 解锁 加锁 UnLock() 、 Lock() 进行设置

示例CCriticalSection CriticalSection; // 建立全局 CCriticalSection 对象,解锁状态UINT Thread1(LPVOID pParam) // 线程 1{

while(1){

CriticalSection.Lock(); // 等待 CCriticalSection 被解锁,// 当函数返回后 CriticalSection 将被锁定

AfxMessageBox(" 线程 1占有临界段,按 <确定 > 放弃临界段 ");CriticalSection.Unlock();

}}

Page 18: Windows 编程技术

18

进程、线程间的同步 使用互斥量 CMutex

用法互斥量与临界段功能基本相同。区别在于:临界段只能用于进程内的同步,互斥量可以用于多个进程间的同步。 状态

解锁 加锁 UnLock() 、 Lock() 进行设置

示例CMutex Mutex(FALSE,"Mutex");UINT Thread(LPVOID pParam){

while(1){

Mutex.Lock();AfxMessageBox(" 线程占有临界段,按 <确定 > 放弃临界段 ");Mutex.Unlock();

}}

Page 19: Windows 编程技术

19

进程、线程间的同步 使用信号量 CSemaphore

用法信号量能够限制应用程序中访问同一资源的线程数。 状态

UnLock() 、 Lock() 进行设置 示例CSemaphore Semaphore(3,3,"Semaphore");UINT Thread(LPVOID pParam){

int ID=IDOK;while(ID==IDOK){

Semaphore.Lock();ID=AfxMessageBox("<确定 > 放弃信号量 ,< 取消 > 退出线程 ", MB_

OKCANCEL);Semaphore.Unlock();

}return 0;

}