并行计算与多核程序设计

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第四章Windows多线程编程及
调优->web课件
返回
在Windows平台下可以通过Windows的线程库来实现多线程编程,可以利用Win32 API或MF C以及.Net Framework提供的接口来实现。

实现方式的多样化给Windows编程带来了很大的灵活性,但也使得多线程编程变得复杂。

对于多线程的程序我们可以使用Visual Studio调试工具进行调试,也可以使用多核芯片厂家的线程分析与调试工具进行调试及优化。

Windows线程库介绍
Win32 API是Windows操作系统为内核以及应用程序之间提供的接口,将内核提供的功能进行函数封装,应用程序通过调用相关的函数获得相应的系统功能。

Win32 API提供了一系列处理线程的函数接口,来向应用程序提供多线程的功能。

MFC是微软基础函数类库(Microsoft Foundation Classes),由微软提供的,用类库的方式将Wi n32 API 进行封装, 以类的方式提供给开发者。

在MFC类库中,提供了对多线程的支持。

由于MF C是在Win32 API 基础之上进行封装的,其基本原理与Win32 API的基本实现原理很类似。

MFC 对同步对象作了封装,因此对用户编程实现来说更加方便。

.NET Framework由两部分构成:公共语言运行库(Common Language Runtime ,CLR)和Fra mework类库(Framework Class Library ,FCL)。

CLR包括自己的文件加载器、垃圾收集器、安全系统等。

CRL提供了一个可靠而完善的多语言运行环境。

CLR是一个软件引擎,用于加载应用程序、检查错误、进行安全许可认证、执行和清空内存。

Framework类库提供了所有应用程序模型都要使用的一个面向对象的API集合。

.NET 基础类库的System.Threading命名空间提供了大量的类和接口来支持多线程。

所有与多线程机制相关的类都存放在System.Threading命名空间中。

其中Thread类用于创建及管理线程,ThreadPool类用于管理线程池等,此外还提供线程间通讯等实际问题的机制。

使用win32线程API
Win32 函数库中提供了操作多线程的函数,包括创建线程、管理线程、终止线程、线程同步等接口。

线程必须从一个指定的函数开始执行,该函数称为线程函数,具有如下原型:
DWORD WINAPI ThreadFunc (LPVOID lpvThreadParm);
线程创建
创建线程的函数如下:
HANDLE CreateThread (
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
CreateThread函数中需要传递6个参数。

下面简单介绍一下这几个参数的用法:
第一个参数lpThreadAtt,是一个指向SECURITY- ATTRIBUTES结构的指针,该结构制定了线程的安全属性,缺省为NULL。

第二个参数dwStackSize,是栈的大小,一般设置为0。

第三个参数lpFun是新线程开始执行时,线程函数的入口地址。

它必须是将要被新线程执行的函数地址,不能为NULL。

第四个参数lpParameter,是线程函数定义的参数。

可以通过这个参数传送值,包括指针或者NULL 。

第五个参数dwCreationFlags,控制线程创建的附加标志,可以设置两种值。

0表示线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
第六个参数lpThreadID,为指向32位变量的指针,该参数接受所创建线程的ID号。

如果创建成功则返回线程的句柄,否则返回NULL。

线程管理
(1)设置线程的优先级
当一个线程被创建时,它的优先级等于它所属进程的优先级。

可以通过调用SetThreadPriority函数来设置线程的相对优先级。

线程的优先级是相对其所属的进程的优先级而言的。

例如:Bool SetThreadPriority (HANDLE hPriority , int nPriority) ;
参数hPriority 是指向待设置的线程句柄,线程与包含它的进程的优先级关系如下:
线程优先级= 进程优先级+ 线程相对优先级
(2)线程的挂起与恢复
进程中的每个线程都有挂起计数器(suspend count) 。

当挂起计数器值为0 时,线程被执行;当挂起计数器值大于0 时,调度器不去调度该线程。

不能够直接访问线程的挂起计数器,可以通过调用Windows API 函数来改变它的值。

可以通过调用SuspendThread()函数来挂起。

可以通过调用ResumeThread()函数来恢复。

这两个函数的原型如下:
DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。

每次调用SuspendThr ead() 函数,线程将挂起计数器的值增1 。

DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态来执行这个线程。

每次调用ResumeThread() 函数,线程将挂起计数器的值减1 ,若挂起计数器的值为0,则不会再减。

(3)线程等待
Win32 API提供了一组能使线程阻塞其自身执行的等待函数WaitForSingleObject、WaitForMulti pleObject。

这些函数在其参数中的一个或多个同步对象产生了信号,或者超过规定的等待时间才会返回。

在等待函数未返回时,线程处于等待状态,线程只消耗很少的CPU时间。

最常用的等待函数是:
DWORD WaitForSingleObject(HANDLE hHandle,
DWORD dwMilliseconds);
而函数WaitForMultipleObject可以用来同时监测多个对象,该函数的声明为:
DWORD WaitForMultipleObject(DWORD nCount,
CONST HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds);
线程终结
在线程函数返回时,线程自动终止。

如果需要在线程的执行过程中终止则可调用函数:VOID ExitThread (DWORD dwExitCode) ;
如果在线程的外面终止线程,则可调用下面的函数:
BOOL TerminateThread (HANDLE hThread, DWORDdw ExitCode) ;
Win32多线程的实现
下面这个程序首先创建两个线程,当输入为1时,执行线程,否则挂起线程。

例4.2 简单的多线程创建、执行、挂起、终止的程序例子
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI FunOne(LPVOID param){
while(true)
{
Sleep(1000);
cout<<"hello! ";
}
return 0;
}
DWORD WINAPI FunTwo(LPVOID param){
while(true)
{
Sleep(1000);
cout<<"world! ";
}
return 0;
}
int main(int argc, char* argv[])
{
int input=0;
HANDLE hand1=CreateThread (NULL, 0, FunOne, (void*)&input, CREATE_SUSPENDED, N ULL);
HANDLE hand2=CreateThread (NULL, 0, FunTwo, (void*)&input, CREATE_SUSPENDED, NULL);
while(true){
cin>>input;
if(input==1)
{
ResumeThread(hand1);
ResumeThread(hand2);
}
else
{
SuspendThread(hand1);
SuspendThread(hand2);
}
};
TerminateThread(hand1,1); TerminateThread(hand2,1); return 0;
}。

相关文档
最新文档