您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 能源与动力工程 > chap2Windows多线程编程.
第二章Windows多线程编程内容1.Windows操作系统的一些基本知识2.Win32API线程库3.线程间通信1、Windows操作系统的一些基本知识1.API2.内核对象及句柄API(ApplicationProgrammingInterface)API:操作系统留给应用程序的一个调用接口,应用程序通过API使操作系统去执行相应程序。WindowsAPI是一套用来控制Windows的各个部件的外观和行为的预先定义的Windows函数。Win32API即为Microsoft32位平台的应用程序编程接口。Win32平台上运行的应用程序都可以调用这些函数。32与64位API函数声明上没有明显区别,但64位编程是需要下载相应的软件开发包SDK。API(ApplicationProgrammingInterface)直接用win32API编写的应用程序,程序的执行代码小,运行效率高MFC用类库的方式将win32API进行封装,以类的方式提供给开发者内核对象及句柄内核对象是由操作系统内核分配,只能由内核访问的数据结构,供系统和应用程序使用来管理各种系统资源。内核对象包括:进程对象、线程对象、事件对象、文件对象、作业对象、互斥对象、等待计时器对象等都是内核对象。出于安全的考虑,进程不能直接访问内核对象。操作系统提供了一组函数来访问内核对象。通过函数创建、打开和操作内核对象。内核对象及句柄内核对象由内核拥有,各个进程可以共享内核对象。进程终止执行,它使用的内核对象并不一定会被撤销。每个内核对象都有一个计数器来存储有多少个进程在使用它的信息。进程调用时,计数器增1,调用结束,计数器减1。内核对象计数器为零时,销毁此内核对象。内核对象及句柄内核对象有安全描述符的保护,安全描述符描述了谁创建了该对象以及谁能够使用该对象。用于创建内核对象的函数几乎都有一个指向SECURITY_ATTRIBUTES结构的指针作为其参数。大多数应用程序通过传NULL值,创建具有默认安全性的对象。如果想限制其他线程对对象的访问,就需要单独创建一个SECURITY_ATTRIBUTES对象并对其初始化。内核对象及句柄句柄:创建内核对象时,函数的返回值,标记该内核对象。句柄表:进程被初始化时,系统给进程分配一个句柄表,用于保存该进程使用的内核对象的信息,而句柄值则是相应内核对象在句柄表中的索引值,因此句柄值是进程相关的。内核对象及句柄内核对象创建当利用creat*函数来创建内核对象时,系统内核就为该对象分配一个内存块,并进行初始化,然后系统内核扫描该进程的句柄表,初始化一条记录并放在句柄表中。关闭内核对象无论进程怎样创建内核对象,在不使用该对象的时候都应当通过BoolCloseHandle(HANDLEhobj)来向操作统声明结束对该对象的访问。Win32API线程库1.创建线程的基本问题2.创建线程的API函数3.操作线程的API4.一个简单的Windows多线程程序1创建线程的基本问题线程可以由进程中的任意线程创建,而进程的主线程在进程加载时自动创建。每个线程都有自己的进入点函数。主线程的进入点函数进入点应用程序类型WinMain需要ANSI字符和字符串的GUI应用程序wWinMain需要Unicode字符和字符串的GUI应用程序Main需要ANSI字符和字符串的CUI应用程序Wmain需要Unicode字符和字符串的CUI应用程序–线程函数的返回值是该线程的退出代码–线程函数应尽可能使用函数参数和局部变量线程函数----线程的入口点DWORDWINAPIThreadFunc(PVOIDpvParam){DWORDdwResult=0;……return(dwResult);}2创建线程的API函数创建线程过程:系统创建一个线程内核对象。线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。在进程的地址空间分配内存,供线程的堆栈使用HANDLECreateThread(PSECURITY_ATTRIBUTESpsa,DWORDcbStack,PTHREAD_START_ROUTINEpStartAddr,PVOIDpvParam,DWORDfdwCreate,PDWORDpdwThreadId);2创建线程的API函数NULL0函数地址函数参数NULL控制创建线程标志CREATE_SUSPENDED0线程ID#includewindows.h#includeiostreamusingnamespacestd;DWORDWINAPIThreadFunc(PVOIDpvParam){coutCreatedthreadsays'helloWorld!'endl;return0;}intmain(){HANDLEThreadHandle=CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);Sleep(100);coutMainthreadsays'HelloWorld!endl;getchar();return0;}暂停线程DWORDSuspendThread(HANDLEhThread)返回值是线程的前一个暂停计数暂停计数:是线程内核对象的一个内部值。使用要小心,因为不知道暂停线程运行时它在进行什么操作。可能造成死锁3操作线程的API3操作线程的API恢复线程DWORDResumeThread(HANDLEhThread);返回值是线程的前一个暂停计数该函数用于将处于暂停状态的线程置于就绪状态,使其参加线程调度。3操作线程的API使线程睡眠VOIDSleep(DWORDdwMilliseconds);该函数是线程暂停自己的运行,直到睡眠时间过去为止。当线程调用这个函数时,它自动放弃剩余的时间片,迫使系统进行线程调度。Windows不是实时的操作系统。3操作线程的API终止线程①线程函数返回(最好)②通过调用ExitThread函数,线程将自行撤销③同一个进程或另一个进程中的线程调用TerminateThread函数④包含线程的进程终止①线程返回函数线程中创建的C++类对象能够正常撤销;操作系统将正确地释放线程堆栈使用的内存;系统将线程的退出代码设置为线程函数的返回值;系统将递减线程内核对象的使用计数。线程调用这个函数,强制线程终止运行;操作系统清除该线程使用的所有系统资源。C++类对象将不被撤销。VOIDExitThread(DWORDdwExitCode);②ExitThread函数能够撤销任何线程;线程的内核对象的使用计数也被递减;异步运行的函数;不撤销线程的堆栈,直到进程终止。BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode);③TerminateThread函数④在进程终止运行时撤销线程ExitProcess和TerminateProcess函数可以终止线程,将会终止进程中的所有线程;ExitProcess只能强制执行本进程的退出;TerminateProcess在一个进程中强制结束其他的进程;进程所使用的资源被清除;C++对象撤销函数没有被调用。VOIDExitProcess(UINTuExitCode);BOOLTerminateProcess(HANDLEhProcess,UINTuExitCode);#includewindows.h#includeiostreamusingnamespacestd;DWORDWINAPIFunOne(LPVOIDparam){int*p=(int*)param;cout(*p)endl;while(true){Sleep(1000);couthello!;}return0;}DWORDWINAPIFunTwo(LPVOIDparam){int*p=(int*)param;cout(*p)endl;while(true){Sleep(1000);coutworld!;}return0;}intmain(intargc,_TCHAR*argv[]){intinput=100;intinput1=100;intinput2=200;HANDLEhand1=CreateThread(NULL,0,FunOne,(void*)&input1,CREATE_SUSPENDED,NULL);input=200;HANDLEhand2=CreateThread(NULL,0,FunTwo,(void*)&input2,CREATE_SUSPENDED,NULL);while(true){cininput;if(input==1){ResumeThread(hand1);ResumeThread(hand2);}else{SuspendThread(hand1);SuspendThread(hand2);}}TerminateThread(hand1,1);TerminateThread(hand2,1);return0;}例打印出100~1000之间的所有“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个“水仙花数”,因为153=13+33+53不需要通信intmain(){inti,j,k,n;printf('水仙花数'是:);for(n=100;n1000;n++){i=n/100;j=n/10-i*10;k=n%10;if(i*100+j*10+k==i*i*i+j*j*j+k*k*k){printf(%d,n);}}printf(\n);getchar();return0;}structbound{intlow;inthigh;};DWORDWINAPIThread1(PVOIDpvParam){inti,j,k,n;bound*bou=(bound*)pvParam;intlow=bou-low;inthigh=bou-high;for(n=low;nhigh;n++){i=n/100;j=n/10-i*10;k=n%10;if(i*100+j*10+k==i*i*i+j*j*j+k*k*k){printf(%d,n);}}return0;}intmain(){printf('水仙花数'是:);boundqw1,qw2;qw1.low=100;qw1.high=500;HANDLEThreadHandle1=CreateThread(NULL,0,Thread1,&qw1,0,NULL);qw2.low=500;qw2.high=1000;HANDLEThreadHandle2=CreateThread(NULL,0,Thread1,&qw2,0,NULL);HANDLEThreadHandles[2]={ThreadHandle1,ThreadHandle2};WaitForMultipleObjects(2,ThreadHandles,TRUE,INFINITE);return0;}线程间通信操作系统随机调度线程,程序员不能预知线程的执行顺序下面两种情况下,线程间需要通信当有多个线程访问共享资源而不希望共享资源遭到破坏;(互斥)当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。(同步)Windows线程通信方法主要有互锁函数、临界段、事件、互斥量、信号量线程间通信1.互锁函数2.临界段3.事件4.互斥量5.信号量使用内核对象的线程间通信互锁函数和临界段都是在用户态实现线程通信的,优点速度快用户态机制只能实现同一进程内线程通信。内核对象机制可以实现不同进程内线程的通信,缺点速度慢。包含通知状态和未通知状态内核属性的内核对象有:进程,线程,作业,文件,控制台输入文件修改通知,事件,可等待定时器信号量,互斥量等待函数:使线程进入等待状态,直到一个对象变
本文标题:chap2Windows多线程编程.
链接地址:https://www.777doc.com/doc-2905091 .html