多进程与多核编程.pdf
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《多进程与多核编程.pdf》由会员分享,可在线阅读,更多相关《多进程与多核编程.pdf(87页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 1 第第 13 章章 多线程与多核多线程与多核编程编程 多任务的并发执行会用到多线程(multithreading),而 CPU 的多核(mult-core)化又将原来只在巨型机中才使用的并行计算(parallel computing)带入普通 PC 应用的多核程序设计(multi-core programming)中。13.1 进程与线程进程与线程 进程(process)是执行中的程序,线程(thread)是一种轻量级的进程。13.1.1 进程进程与多任务与多任务 现代的操作系统都是多任务(multitask)的,即可同时运行多个程序。进程(process)是位于内存中正被 CPU 运行的
2、可执行程序。参见图 15-1。图 15-1 程序与进程 目前的主流计算机采用的都是冯诺依曼(John von Neumann)体系结构存储程序计算模型,程序(program)就是在内存中顺序存储并以线性模式在 CPU 中串行执行的指令序列。对于传统的单核 CPU 计算机,多任务操作系统的实现是通过 CPU 分时(time-sharing)和程序并发(concurrency)完成的。即在一个时间段内,操作系统将 CPU 分配给不同的程序,虽然每一时刻只有一个程序在 CPU 中运行,但是由于 CPU 的速度非常快,在很短的时间段中可在多个进程间进行多次切换,所以用户的感觉就像多个程序在同时执行,我
3、们称之为多任务的并发。13.1.2 进程与线程进程与线程 程序一般包括代码段、数据段和堆栈,对具有 GUI(Graphical User Interfaces,图形用户界面)的程序还包含资源段。进程(process)是应用程序的执行实例,即正在被执行的程序。每个进程都有自己的虚拟地址空间,并拥有操作系统分配给它的一组资源,包括堆栈、寄存器状态等。线程(thread)是 CPU 的调度单位,是进程中的一个可执行单元,是一条独立的指令执行路径。线程只有一组 CPU 指令、一组寄存器和一个堆栈,它本身没有其他任何资源,而是与拥有它的进程共享几乎一切,包括进程的数据、资源和环境变量等。线程的创建、维护
4、和管理给操作系统的负担比进程要轻得多,所以才叫轻量级的进程(lightweight process)。一个进程可以拥有多个线程,而一个线程只能属于一个进程。每个进程至少包含一个线程主线程,它负责程序的初始化工作,并执行程序的起始指令。随后,主线程可为执行各种不同的任务而分别创建多个子线程。一个程序的多个运行,可以通过启动该程序的多个实例(即多个进程)来完成,也可以程序=进程(内存中)可执行文件(磁/U/光盘上)运行 2 只运行该程序的一个实例(一个进程),而由该进程创建多个线程来做到。显然后者要比前者更高效,更能节约系统的有限资源。这对需要在同一时刻响应成千上万个用户请求的 Web服务器程序和
5、网络数据库管理程序等来说是至关重要的。多线程图示 其中:A 为主线程,B、C、D 皆为 A 的子线程 不同并行任务中的同名子线程可以互不相同 有关进程和线程的进一步内容,大家会在将来的操作系统课程中学到。13.1.3 多线程编程的困难多线程编程的困难 因为同一程序(进程)的多个线程共享同样的数据和资源,所以会出现同步、排队和竞争等问题,可能导致死锁、无限延迟和数据竞争等现象的发生,这些都需要我们在程序中加以解决。MFC 虽然提供了一个线程类和若干同步类,但是仍然属于线程的低级编程,既困难又繁琐。利用.NET 框架类库中的线程命名空间下的线程类,则可以简化线程编程。13.2 MFC 的进程和线程
6、编程的进程和线程编程 使用传统的 MFC/C+直接进行进程和线程编程异常复杂和繁琐,需要程序员自己处理线程间的同步、互斥、死锁等具体问题。13.2.1 创建创建、管理、管理和终止和终止进程进程 MFC 中并没有提供处理进程的类,我们需要直接使用 Windows 的 API 函数来创建、管理和终止进程。1创建进程创建进程 下面的 CreateProcess 函数用于在当前进程中创建一个新进程(和其主线程),以运行指定(路径/文件名或命令行)的应用程序:3 BOOL CreateProcess(/成功返回非 0,失败返回 0(可用 GetLastError 函数返回出错代码)LPCTSTR lpA
7、pplicationName,/可执行文件的全路径或文件名,有命令行时可为 NULL LPTSTR lpCommandLine,/命令行参数字符串,有可应用名时可为 NULL LPSECURITY_ATTRIBUTES lpProcessAttributes,/进程的安全属性,NULL 表默认安全 LPSECURITY_ATTRIBUTES lpThreadAttributes,/主线程的安全属性,NULL 表默认安全 BOOL bInheritHandles,/子进程是否继承新进程的句柄 DWORD dwCreationFlags,/创建标志,用于设置进程的创建状态和优先级别,可为 0 LP
8、VOID lpEnvironment,/环境变量,为 NULL 时同当前进程的 LPCTSTR lpCurrentDirectory,/进程运行的当前目录,为 NULL 时同当前进程的 LPSTARTUPINFO lpStartupInfo,/指向设置进程主窗口或控制条的各种属性的结构指针 LPPROCESS_INFORMATION lpProcessInformation/指向返回进程信息的结构指针);其中,结构 STARTUPINFO 和 PROCESS_INFORMATION 的定义分别为:typedef struct _STARTUPINFO DWORD cb;/结构的长度(字节数)L
9、PTSTR lpReserved;/保留,必须为 NULL LPTSTR lpDesktop;/桌面-窗口站的名称 LPTSTR lpTitle;/控制台进程的标题 DWORD dwX;/窗口位置的横坐标 DWORD dwY;/窗口位置的纵坐标 DWORD dwXSize;/窗口的水平尺寸 DWORD dwYSize;/窗口的垂直尺寸 DWORD dwXCountChars;/控制台窗口的屏幕缓冲区宽度(字符数)DWORD dwYCountChars;/控制台窗口的屏幕缓冲区高度(字符数)DWORD dwFillAttribute;/控制台窗口的初始文本和背景色 DWORD dwFlags;/
10、窗口的创建标志 WORD wShowWindow;/用作窗口显示函数 ShowWindow 的缺省参数 WORD cbReserved2;/保留,必须为 0 LPBYTE lpReserved2;/保留,必须为 NULL HANDLE hStdInput;/标准输入的句柄 HANDLE hStdOutput;/标准输出的句柄 HANDLE hStdError;/标准错误的句柄 STARTUPINFO,*LPSTARTUPINFO;和 typedef struct _PROCESS_INFORMATION HANDLE hProcess;/返回的进程句柄 HANDLE hThread;/返回的主
11、线程句柄 DWORD dwProcessId;/返回的进程 ID DWORD dwThreadId;/返回的主线程 ID PROCESS_INFORMATION,*LPPROCESS_INFORMATION;2管理进程管理进程 1)获取进程的句柄和 ID 除了可从创建进程函数 CreateProcess 的最后一个(返回)参数进程信息结构 4 PROCESS_INFORMATION 变量来获取所创建的新进程及其主线程的句柄和 ID 外,还可利用 API 函数 GetCurrentProcess 和 GetCurrentProcessId 来获取当前进程的句柄和 ID:HANDLE GetCur
12、rentProcess(void);DWORD GetCurrentProcessId(void);不过用 GetCurrentProcess 返回的是一个伪句柄,只能在当前进程中使用。可以调用 API 函数 DuplicateHandle 将此伪句柄转换为一个真正的句柄。2)获取和设置进程的优先级 在 Windows 操作系统中,进程有 6 种优先级别(priority level/class),从低到高分别为:空闲(Idel)、低普通(Below normal)、普通(Normal)、高普通(Above normal)、高(High)和实时(Real time),对应的符号常量为:表 15
13、-1 进程优先级符号常量 符号常量 对应数值 IDLE_PRIORITY_CLASS 0 x00000040 BELOW_NORMAL_PRIORITY_CLASS 0 x00004000 NORMAL_PRIORITY_CLASS 0 x00000020 ABOVE_NORMAL_PRIORITY_CLASS 0 x00008000 HIGH_PRIORITY_CLASS 0 x00000080 REALTIME_PRIORITY_CLASS 0 x00000100 可以在创建新进程时,利用其创建标志参数 dwCreationFlags 来设置。也可以用 API 函数 GetPriority
14、Class 和 SetPriorityClass 来获取和设置指定进程的优先级:DWORD GetPriorityClass(HANDLE hProcess);BOOL SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass);例如:DWORD p=GetPriorityClass(GetCurrentProcess();SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS);3)等待进程返回 可以调用 API 函数 WaitForSingleObject 来等待指定进程(或线程)
15、结束后返回:DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);例如:WaitForSingleObject(pi.hProcess,INFINITE);3结束进程结束进程 结束进程的方法有多种,可以调用 API 函数 ExitProcessk 来结束当前进程(及其所有线程):(对控制台程序,在接收到 CTRL+C 或 CTRL+BREAK 信号后会调用此函数)VOID ExitProcess(UINT uExitCode);或调用 API 函数 ExitProcess 来结束指定进程(及其所有线程):BO
16、OL TerminateProcess(HANDLE hProcess,UINT uExitCode);进程的所有线程终止后进程也会自动终止。在用户关闭系统或注销推出系统时,也会导致进程终止。在结束进程后,还需要调用 API 的 CloseHandle 函数来删除进程和线程对象:BOOL CloseHandle(HANDLE hObject);例如:CloseHandle(pi.hProcess);CloseHandle(pi.hThread);4例子例子 5 下面是一个控制台程序,在该程序中,创建一个新进程来运行指定的另一个可执行程序。为此,需要创建一个名为 Process 的“Visual
17、 C+/常规/空项目”,并将如下代码文件添加到此项目中:/Process.cpp#include#include#include void _tmain()STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si,sizeof(si);si.cb=sizeof(si);ZeroMemory(&pi,sizeof(pi);/Start the child process.if(!CreateProcess(E:CDPlay.exe,/Module name(须换成你自己磁盘上的某个可执行文件的路径)NULL,/No Command line(use
18、 module name)NULL,/Process handle not inheritable NULL,/Thread handle not inheritable FALSE,/Set handle inheritance to FALSE 0,/No creation flags NULL,/Use parents environment block NULL,/Use parents starting directory&si,/Pointer to STARTUPINFO structure&pi)/Pointer to PROCESS_INFORMATION structure
19、 )printf(CreateProcess failed(%d)n,GetLastError();return;/Wait until child process exits.WaitForSingleObject(pi.hProcess,INFINITE);/Close process and thread handles.CloseHandle(pi.hProcess);CloseHandle(pi.hThread);13.2.2 创建、管理和终止线程创建、管理和终止线程 MFC 中提供了线程类 CWinThread,参见图 15-2。在 MFC图 15-2 CWinThread 类 及
20、其派生类 6 中区分两种类型的线程:用户界面线程(user-interface thread)和辅助线程(worker thread)。用户界面线程通常用于处理用户输入及响应用户生成的事件和消息。辅助线程通常用于完成不需要用户输入的任务(如重新计算)。Win32 API 则不区分线程类型;它只需要了解线程的起始地址以开始执行线程。MFC 为用户界面中的事件提供消息泵(message pump),从而对用户界面线程进行专门处理。CWinApp 是用户界面线程对象的一个示例,因为它从CWinThread 派生并对用户生成的事件和消息进行处理。1创建创建线程线程 MFC 应用程序中的所有线程都由 C
21、WinThread 对象表示。大多数情况下,甚至不必显式创建这些对象,而只需调用 MFC 框架的助手型全局函数 AfxBeginThread,该函数将自动创建 CWinThread 对象。也可以先创建自己的线程(C+)对象,再利用线程类的成员函数CreateThread 来创建 Windows 线程。1)利用全局函数 AfxBeginThread 创建线程 AfxBeginThread 函数有两个版本,分别用于创建用户界面线程和辅助线程:CWinThread*AfxBeginThread(/创建用户界面线程 CRuntimeClass*pThreadClass,int nPriority=TH
22、READ_PRIORITY_NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL );CWinThread*AfxBeginThread(/创建辅助线程 AFX_THREADPROC pfnThreadProc,LPVOID pParam,int nPriority=THREAD_PRIORITY_NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NU
23、LL );例如:class CMyThread:public CWinThread CMyThread*pMyThread=(CMyThread*)AfxBeginThread(RUNTIME_CLASS(CSockThread);if(pMyThread!=NULL)pMyThread-ResumeThread();及 UINT WorkerThread(LPVOID pParam)CWnd*pWin=(CWnd*)pParam;AfxBeginThread(WorkerThread,this);2)利用 CWinThread 类的 CreateThread 函数创建线程 可以先从 CWin
24、Thread 类派生自己的线程类,再利用 CWinThread 的成员函数 7 CreateThread 来创建线程:BOOL CreateThread(DWORD dwCreateFlags=0,UINT nStackSize=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL );例如:class CMyThread:public CWinThread CMyThread*pMyThread=new CMyThread;pMyThread-CreateThread();实际上,1)中的 AfxBeginThread 函数也是通过先创建一个 CWinTh
25、read 对象,再调用其 CreateThread 函数来完成线程创建的。2管理线程管理线程 1)获取线程对象 可以利用 MFC 的全局函数 AfxGetThread 来获取当前的线程对象:CWinThread*AfxGetThread();2)获取和设置线程优先级 利用 CWinThread 类的成员函数 GetThreadPriority 和 SetThreadPriority 可以获取和设置线程的优先级:int GetThreadPriority();BOOL SetThreadPriority(int nPriority);线程的优先级是在其所属进程优先级的基础上的一种相对优先级,nP
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 进程 多核 编程
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内