多核程序设计chap2wi多线程编程_第1页
多核程序设计chap2wi多线程编程_第2页
多核程序设计chap2wi多线程编程_第3页
多核程序设计chap2wi多线程编程_第4页
多核程序设计chap2wi多线程编程_第5页
已阅读5页,还剩111页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第二章Windows多线程编程内容Windows操作系统的一些基本知识创建Windows线程线程间通信1、Windows操作系统的一些基本知识API内核对象及句柄API(ApplicationProgrammingInterface)API:操作系统留给应用程序的一个调用接口,应用程序通过API使操作系统去执行相应程序。WindowsAPI是一套用来控制Windows的各个部件的外观和行为的预先定义的Windows函数。直接用WindowsAPI编写的应用程序,程序的执行代码小,运行效率高内核对象及句柄内核对象是由操作系统内核分配,只能由内核访问的数据结构,供系统和应用程序使用来管理各种系统资源。内核对象包括:进程对象、线程对象、事件对象、文件对象、作业对象、互斥对象、等待计时器对象等都是内核对象。出于安全的考虑,进程不能直接访问内核对象。操作系统提供了一组函数来访问内核对象。通过函数创建、打开和操作内核对象。内核对象及句柄内核对象由内核拥有,各个进程可以共享内核对象。进程终止执行,它使用的内核对象并不一定会被撤销。每个内核对象都有一个计数器来存储有多少个进程在使用它的信息。进程调用时,计数器增1,调用结束,计数器减1。内核对象计数器为零时,销毁此内核对象。

内核对象及句柄内核对象有安全描述符的保护,安全描述符描述了谁创建了该对象以及谁能够使用该对象。用于创建内核对象的函数几乎都有一个指向SECURITY_ATTRIBUTES

结构的指针作为其参数。

大多数应用程序通过传NULL值,创建具有默认安全性的对象。如果想限制其他线程对对象的访问,就需要单独创建一个SECURITY_ATTRIBUTES对象并对其初始化。内核对象及句柄句柄:创建内核对象时,函数的返回值,标记该内核对象。句柄表:进程被初始化时,系统给进程分配一个句柄表,用于保存该进程使用的内核对象的信息,而句柄值则是相应内核对象在句柄表中的索引值,因此句柄值是进程相关的。内核对象及句柄内核对象创建当利用creat*函数来创建内核对象时,系统内核就为该对象分配一个内存块,并进行初始化,然后系统内核扫描该进程的句柄表,初始化一条记录并放在句柄表中。关闭内核对象无论进程怎样创建内核对象,在不使用该对象的时候都应当通过Bool

CloseHandle(HANDLE

hobj)来向操作统声明结束对该对象的访问。2.创建Windows线程主线程和子线程创建线程控制线程终止线程等待函数一个简单的Windows多线程程序2.1主线程和子线程线程可以由进程中的任意线程创建,而进程的主线程在进程加载时自动创建。每个线程都有自己的进入点函数。主线程的进入点函数进入点应用程序类型WinMain需要ANSI字符和字符串的GUI应用程序wWinMain需要Unicode字符和字符串的GUI应用程序Main需要ANSI字符和字符串的CUI应用程序Wmain需要Unicode字符和字符串的CUI应用程序线程函数的返回值是该线程的退出代码线程函数应尽可能使用函数参数和局部变量2.1主线程和子线程线程函数----线程的入口点DWORDWINAPIThreadFunc(PVOIDpvParam){ DWORDdwResult=0; … … return(dwResult);}2.3创建线程创建线程过程:系统创建一个线程内核对象。线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。在进程的地址空间分配内存,供线程的堆栈使用HANDLECreateThread(PSECURITY_ATTRIBUTESpsa,DWORDcbStack,PTHREAD_START_ROUTINEpStartAddr,PVOIDpvParam,DWORDfdwCreate,PDWORDpdwThreadId);2.3创建线程NULL0函数地址函数参数NULL控制创建线程标志CREATE_SUSPENDED0线程ID#include"windows.h"#include<iostream>usingnamespacestd;DWORDWINAPIThreadFunc(PVOIDpvParam){

cout<<"Createdthreadsays'helloWorld!'"<<endl;

return0;}intmain(){

HANDLEThreadHandle=CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);

Sleep(100);

cout<<"Mainthreadsays'HelloWorld!"<<endl;

getchar();

return0;}暂停线程DWORDSuspendThread(HANDLEhThread)返回值是线程的前一个暂停计数暂停计数:是线程内核对象的一个内部值。使用要小心,因为不知道暂停线程运行时它在进行什么操作。可能造成死锁2.4控制线程2.4控制线程恢复线程DWORDResumeThread(HANDLEhThread);返回值是线程的前一个暂停计数该函数用于将处于暂停状态的线程置于就绪状态,使其参加线程调度。2.4控制线程使线程睡眠VOIDSleep(DWORDdwMilliseconds);该函数是线程暂停自己的运行,直到睡眠时间过去为止。当线程调用这个函数时,它自动放弃剩余的时间片,迫使系统进行线程调度。Windows不是实时的操作系统。2.5终止线程终止线程线程函数返回(最好)通过调用ExitThread函数,线程将自行撤销同一个进程或另一个进程中的线程调用TerminateThread函数包含线程的进程终止2.5终止线程线程返回函数线程中创建的C++类对象能够正常撤销;操作系统将正确地释放线程堆栈使用的内存;系统将线程的退出代码设置为线程函数的返回值;系统将递减线程内核对象的使用计数。ExitThread函数线程调用这个函数,强制线程终止运行;操作系统清除该线程使用的所有系统资源。C++类对象将不被撤销。VOIDExitThread(DWORDdwExitCode);2.5终止线程TerminateThread函数能够撤销任何线程;线程的内核对象的使用计数也被递减;异步运行的函数;不撤销线程的堆栈,直到进程终止。BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode);2.5终止线程2.5终止线程在进程终止运行时撤销线程ExitProcess和TerminateProcess函数将终止进程中的所有线程;ExitProcess只能强制本进程的退出;TerminateProcess在一个进程中强制结束其他进程;进程所使用的资源被清除;C++对象撤销函数没有被调用。VOIDExitProcess(UINTuExitCode);BOOLTerminateProcess(HANDLEhProcess,UINTuExitCode);#include<windows.h>#include<iostream>usingnamespacestd;DWORDWINAPIFunOne(LPVOIDparam){

int*p=(int*)param;

cout<<(*p)<<endl;while(true)

{

Sleep(1000);

cout<<"hello!";

}

return0;}DWORDWINAPIFunTwo(LPVOIDparam){

int*p=(int*)param;

cout<<(*p)<<endl;

while(true)

{

Sleep(1000);

cout<<"world!";

}

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){

cin>>input;

if(input==1)

{

ResumeThread(hand1);

ResumeThread(hand2);

}

else

{

SuspendThread(hand1);

SuspendThread(hand2);

}

}

TerminateThread(hand1,1);

TerminateThread(hand2,1);

return0;}在fork-join模型下,主线程创建多个子线程,并等待子线程退出。利用等待函数来等待子线程退出:WaitForSingleObjectWaitForMultipleObject2.5等待函数等待函数:使线程进入等待状态,直到一个对象变为已通知状态。DWORDWaitForSingleObject(

HANDLEhHandle,

DWORDdwMilliseconds

);参数dwMilliseconds有两个特殊值:0,则该函数立即返回;INFINITE,则线程被挂起,直到hHandle所指向的对象变为已通知状态。2.5等待函数等待函数:可以保证线程的同步。DWORDWaitForMultipleObject(DWORDdwCount,

CONSTHANDLE*phHandle,BOOLfWaitAll,

DWORDdwMilliseconds

);2.5等待函数#include<windows.h>#include<iostream>usingnamespacestd;DWORDWINAPIFunOne(LPVOIDparam){cout<<"helloworld!";return0;}2.5等待函数intmain(intargc,_TCHAR*argv[]){

HANDLEhd[2];for(inti=0;i<2;i++){hd[i]=CreateThread(NULL,0,FunOne,0,0,NULL);

}

for(inti=0;i<2;i++){WaitForSingleObject(h[i],INFINITE);CloseHandle(h[i]);

}getchar();}intmain(intargc,_TCHAR*argv[]){

HANDLEhd[2];for(inti=0;i<2;i++){hd[i]=CreateThread(NULL,0,FunOne,0,0,NULL);

}

WaitForMultipleObject(h,INFINITE);for(inti=0;i<2;i++){CloseHandle(h[i]);

}getchar();}2.6一个简单的Windows多线程程序打印出100~1000之间的所有“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个“水仙花数”,因为153=13+33+53不需要通信intmain(){

inti,j,k,n;

printf("'水仙花数'是:");

for(n=100;n<1000;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;n<high;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;}3线程间通信操作系统随机调度线程,程序员不能预知线程的执行顺序下面两种情况下,线程间需要通信当有多个线程访问共享资源而不希望共享资源遭到破坏;(互斥)当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。(同步)Windows线程通信方法主要有互锁函数、临界段、事件、互斥量、信号量3线程间通信互锁函数临界区事件互斥量信号量Longg_x=0;//全局变量DWORDWINAPIThreadFunc1(PVOIDpvParam){ g_x++;return0;}DWORDWINAPIThreadFunc2(PVOIDpvParam){ g_x++;return0;}MOVEAX,[g_x]INCEAXMOV[g_x],EAX3.1互锁函数3.1互锁函数互锁函数是用来解决原子访问的,主要针对变量的原子访问;原子访问:当线程访问资源时,能够确保没有其它线程同时访问相同的资源。LONGInterlockedExchangeAdd()(PLONGplAddend,LONGlIncrement);3.1互锁函数Longg_x=0;//全局变量DWORDWINAPIThreadFunc1(PVOIDpvParam){ InterlockedExchangeAdd(&g_x,1);return0;}DWORDWINAPIThreadFunc2(PVOIDpvParam){ InterlockedExchangeAdd(&g_x,1);return0;}3.1互锁函数以原子操作方式用第二个参数的值取代第一个参数的当前值。LONGInterlockedExchange()(PLONGplTarget,LONGlValue);LONGInterlockedExchangePointer()(PVOID*ppvTarget,PVOIDpvValue);3.1互锁函数比较第一个参数所指的值和第三个参数的值,如果相等,则将第一个参数所指的值置为第二个参数,如果不相等则不进行任何操作。LONGInterlockedCompareExchange()(PLONGplDestination,LONGlExchange,LONGlComparand);LONGInterlockedCompareExchangePointer()(PVOID*ppvDestination,PVOIDpvExchange,PVOIDpvComparand);例:10000个2相加intmain(){

intsum=0;

for(inti=1;i<=10000;i++)

{

sum=sum+2;

}

printf("10000个2相加之和是%d",sum);

getchar();

return0;}#include"windows.h"longsum=0;DWORDWINAPIThread1(PVOIDpvParam){

for(inti=1;i<=5000;i++)

{//

InterlockedExchangeAdd(&sum,2);

sum=sum+2;

}

return0;}DWORDWINAPIThread2(PVOIDpvParam){

for(inti=5001;i<=10000;i++)

{//

InterlockedExchangeAdd(&sum,2);

sum=sum+2;

}

return0;}intmain(){

HANDLEThreadHandle1=CreateThread(NULL,0,Thread1,NULL,0,NULL);

HANDLEThreadHandle2=CreateThread(NULL,0,Thread2,NULL,0,NULL);HANDLEThreadHandles[2]={ThreadHandle1,ThreadHandle2};WaitForMultipleObjects(2,ThreadHandles,TRUE,INFINITE);

printf("10000个2相加之和是%d",sum);

getchar();

return0;}3.2临界区互锁函数:以原子操作方式修改单个值临界区:以原子方式修改复杂的数据结构。临界区:关键代码段,是指一小段代码,同一个时刻,只能有一个线程具有访问权。多个线程访问同一个临界区的原则:一次最多只能一个线程停留在临界区内;不能让一个线程无限地停留在临界区内,否则其它线程将不能进入该临界区首先定义一个临界段对象(通常全局变量)CRITICAL_SECTIONcs临界段对象初始化InitializeCriticalSection(&cs)

进入临界段EnterCriticalSection(&cs)离开临界段LeaveCriticalSection(&cs)释放临界段对象DeleteCriticalSection(&cs)3.2临界区临界区例1#include<windows.h>#include<fstream>fstreamfile;DWORDWINAPIThreadFunc1(PVOIDparam){ for(inti=1;i<=1000;i++) {

file<<"ThreadFunc1Output"<<i<<endl; } return0;}DWORDWINAPIThreadFunc2(PVOIDparam){ for(inti=1;i<=1000;i++) {

file<<"ThreadFunc2Output"<<i<<endl; } return0;}intmain(){

file.open("data.txt",ios::out); HANDLEThreadHandle1=CreateThread(NULL,0,ThreadFunc1,NULL,0,NULL); HANDLEThreadHandle2=CreateThread(NULL,0,ThreadFunc2,NULL,0,NULL); HANDLEhThread[2]={ThreadHandle1,ThreadHandle2}; WaitForMultipleObjects(2,hThread,TRUE,INFINITE);

file.close();

return0;}加上临界区#include<windows.h>#include<fstream>fstreamfile;CRITICAL_SECTIONcs;DWORDWINAPIThreadFunc1(PVOIDparam){ for(inti=1;i<=1000;i++) {

EnterCriticalSection(&cs);

file<<"ThreadFunc1Output"<<i<<endl;

LeaveCriticalSection(&cs); } return0;}DWORDWINAPIThreadFunc2(PVOIDparam){ for(inti=1;i<=1000;i++) {

EnterCriticalSection(&cs);

file<<"ThreadFunc2Output"<<i<<endl;

LeaveCriticalSection(&cs); } return0;}#include“windows.h“例2CRITICAL_SECTIONg_cs;charg_cArray[10];//共享资源DWORDWINAPIThreadProc1(PVOIDpParam){

EnterCriticalSection(&g_cs);

for(inti=0;i<10;i++)

{

g_cArray[i]='a';//对共享资源进行写入操作

Sleep(1);

}

LeaveCriticalSection(&g_cs);

return0;}DWORDWINAPIThreadProc2(PVOIDpParam){

EnterCriticalSection(&g_cs);

for(inti=0;i<10;i++)

{

g_cArray[10-i-1]='b';//对共享资源进行写操作

Sleep(1);

}

LeaveCriticalSection(&g_cs);

return0;}intmain(){

InitializeCriticalSection(&g_cs);

HANDLEThreadHandle1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);

HANDLEThreadHandle2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);HANDLEThreadHandles[2]={ThreadHandle1,ThreadHandle2};WaitForMultipleObjects(2,ThreadHandles,TRUE,INFINITE);

DeleteCriticalSection(&g_cs);

printf(g_cArray);

getchar();

return0;}3.2临界区使线程休眠再唤醒线程非常耗时。所有临界区在设计上都应保证耗时尽可能短。避免让线程休眠:TryEnterCriticalSection()while(counter<100){

while(!TryEnterCriticalSection(&cs)){}intnumber=counter++;

LeaveCriticalSection(&cs);}3.2临界区让想进入临界区的线程短暂旋转,期望临界区的当线程会很快离开。否则,线程旋转预订次数后进入休眠状态,直到另一个线程离开临界区。设置旋转次数:InitializeCriticalSectionAndSpinCount(&cs,1000);SetCriticalSectionSpinCount(&cs,1000);3.3事件事件用于向一个或多个线程发出信号,表明某个事件已经发出。事件内核对象使用计数事件类型(布尔值)自动复位事件(false)人工复位事件(true)事件状态(布尔值)通知状态(true)未通知状态(false)

3.3事件人工复位事件被设置为通知状态等待该事件的所有线程均变为可调度事件,而且一直保持为通知状态,直到重新把它设置为未通知状态。自动复位事件被设置为通知状态等待该事件的线程中只有一个线程变为可调度线程。然后自动恢复为未通知状态。创建事件内核对象,返回句柄。HANDLECreateEvent(

PSECURITY_ATTRIBUTESpsa,//安全属性

BOOLfManualReset,//复位方式

BOOLfInitialState,//初始状态

PCTSTRpszName//对象名称

);3.3事件打开一个已经存在的命名事件对象

HANDLEOpenEvent(

DWORDfdwAccess,

BOOLfInherit,

PCTSTRpszName

);3.3事件EVENT_ALL_ACCESS要求对事件对象进行完全访问EVENT_MODIFY_STATE允许SetEvent

ResetEvent函数SYNCHRONIZE允许事件对象的使用同步一旦事件已经创建,就可以直接控制它的状态将事件设置为已通知状态BOOLSetEvent(HANDLEhEvent);将事件设置为未通知状态BOOLResetEvent(HANDLEhEvent);3.3事件3.3事件事件的主要用途是标志事件的发生,并以此协调线程的执行顺序。例1:用户在主线程输入命令,控制新建线程的运行。#include<windows.h>#include<iostream>#include<string>usingnamespacestd;CRITICAL_SECTIONcs;DWORDWINAPIThreadFunc(PVOIDparam){EnterCriticalSection(&cs);cout<<"CreateThread:Createthreadisstarted"<<endl;cout<<"CreateThread:Createthreadiswaitingcontinuecommand.."<<endl;LeaveCriticalSection(&cs);HANDLEphEvent=OpenEvent(EVENT_ALL_ACCESS,TRUE,"ContinueCommand");WaitForSingleObject(phEvent,INFINITE);cout<<"CreateThread:Recievedcontinuecommand."<<endl;cout<<"CreateThread:Threadrunsagain."<<endl;Sleep(2000);cout<<"CreateThread:Threadfinished."<<endl;return0;}例1intmain(){ InitializeCriticalSection(&cs); HANDLEhEvent=CreateEvent(NULL,FALSE,FALSE,"ContinueCommand"); cout<<"MainThread:Creatingnewthread."<<endl; HANDLEThreadHandle=CreateThread(NULL,0,ThreadFunc,NULL,CREATE_SUSPENDED,NULL); cout<<"MainThread:Newthreadcreated."<<endl; ResumeThread(ThreadHandle); stringinput; while(TRUE) { EnterCriticalSection(&cs); cout<<"MainThread:inputcommand,please"<<endl; LeaveCriticalSection(&cs); cout<<">";

cin>>input; if(input=="continue") { cout<<"MainThread:Letthreadcontinuerun"<<endl; SetEvent(hEvent); break; } }

WaitForSingleObject(ThreadHandle,INFINITE); cout<<"MainThread:Createthreadfinished"<<endl; DeleteCriticalSection(&cs); CloseHandle(hEvent); return0;}例2设计简单的文字管理软件,要求实现功能,读文件、字数统计、拼写检查、语法检查#include<windows.h>HANDLEg_hEvent;voidOpenFileAndReadContentsIntoMemory(){

printf("OpenFileandReadcontentsintomemory\n");}DWORDWINAPIWordCount(PVOIDpvParam){WaitForSingleObject(g_hEvent,INFINITE);printf("0:wordcount\n");

SetEvent(g_hEvent);//自动

return(0);}DWORDWINAPISpellCheck(PVOIDpvParam){WaitForSingleObject(g_hEvent,INFINITE);printf("1:Spellcheck\n");//Accessthememoryblock.

SetEvent(g_hEvent);//自动

return(0);}DWORDWINAPIGrammarCheck(PVOIDpvParam){

WaitForSingleObject(g_hEvent,INFINITE);printf("2:Grammarcheck\n");//Accessthememoryblock.

SetEvent(g_hEvent);//自动

return(0);}intmain(){//g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//人工重置

g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//自动重置HANDLEhThread[3];

DWORDdwThreadID[3];

hThread[0]=CreateThread(NULL,0,WordCount,NULL,0,&dwThreadID[0]);

hThread[1]=CreateThread(NULL,0,SpellCheck,NULL,0,&dwThreadID[1]);

hThread[2]=CreateThread(NULL,0,GrammarCheck,NULL,0,&dwThreadID[2]);

OpenFileAndReadContentsIntoMemory();

//Allowall3threadstoaccessthememory.

SetEvent(g_hEvent);

WaitForMultipleObjects(3,

hThread,

TRUE,INFINITE);

printf("mainthreadexit\n");

getchar();

return0;}例3:协调两个线程执行顺序读操作、写操作先写后读HANDLEevRead,evFinish;DWORDWINAPIReadThread(PVOIDparam){

WaitForSingleObject(evRead,INFINITE);

cout<<"Reading"<<endl;

SetEvent(evFinish);}DWORDWINAPIWriteThread(PVOIDparam){

cout<<"Writing"<<endl;

SetEvent(evRead);}intmain(){

evRead=CreateEvent(NULL,FALSE,FALSE,NULL);

evFinish=CreateEvent(NULL,FALSE,FALSE,NULL);CreateThread(NULL,0,ReadThread,NULL,0,NULL);CreateThread(NULL,0,WriteThread,NULL,0,NULL);

WaitForSingleObject(evFinish,INFINITE);

cout<<"TheProgramisEnd"<<endl;

return0;}3.4互斥量互斥量是一个种内核对象,确保线程拥有对单个资源的互斥访问权。一个使用数量一个线程ID一个递归计数器互斥量的线程ID标识系统中哪个线程拥有互斥量,为0,没有线程拥有递归计数器指明线程拥有互斥量的次数3.4互斥量经常用于保护多个线程访问的内存块;控制对共享资源的访问保证每次只能有一个线程获得互斥量3.4互斥量互斥量的创建,返回句柄HANDLECreateMutex(PSECURITY_ATTRIBUTESpsa,//安全属性的指针

BOOLbInitialOwner,//初始化互斥对象的所有者

PCTSTRpszName

//指向互斥对象名的指针

);InitialOwner:FALSE,互斥对象的线程ID和递归计数器均被设置为0。TRUE,互斥对象的线程ID被设置为调用线程的ID,递归计数器被设置为1。3.4互斥量为现有的一个已命名互斥对象创建一个新句柄

HANDLEOpenMutex(

DWORDfdwAccess,//access

BOOLbInheritHandle,//inheritanceoption

PCTSTRpszName//objectname

);MUTEX_ALL_ACCESS请求对互斥对象的完全访问MUTEX_MODIFY_STATE允许使用ReleaseMutex函数SYNCHRONIZE允许使用互斥对象同步释放互斥量HANDLEReleaseMutex(

HANDLEhMutex

);等待互斥量DWORDWaitForSingleObject(

HANDLEhHandle,

DWORDdwMilliseconds

);互斥量不同于其它内核对象,互斥对象有一个“线程所有权”的概念。3.4互斥量#include<windows.h>#include<fstream>usingnamespacestd;fstreamfile;DWORDWINAPIThreadFunc1(PVOIDparam){ HANDLE*phMutex=(HANDLE*)param; for(inti=1;i<=100;i++) { WaitForSingleObject(*phMutex,INFINITE); file<<"ThreadFunc1Output"<<i<<endl; ReleaseMutex(*phMutex); } return0;}例1DWORDWINAPIThreadFunc2(PVOIDparam){ HANDLE*phMutex=(HANDLE*)param; for(inti=1;i<=100;i++) { WaitForSingleObject(*phMutex,INFINITE); file<<"ThreadFunc2Output"<<i<<endl; ReleaseMutex(*phMutex); } return0;}intmain(){ file.open("data.txt",ios::out); HANDLEhMutex=CreateMutex(NULL,FALSE,"DisplayMutex"); HANDLEThreadHandle1=CreateThread(NULL,0,ThreadFunc1,&hMutex,0,NULL); HANDLEThreadHandle2=CreateThread(NULL,0,ThreadFunc2,&hMutex,0,NULL); HANDLEhThread[2]={ThreadHandle1,ThreadHandle2}; WaitForMultipleObjects(2,hThread,TRUE,INFINITE); CloseHandle(hMutex); file.close(); return0;}比较临界区、互斥量、事件给数组元素赋值,并在屏幕打印出来改变起始值,无限重复上述过程#include"windows.h"CRITICAL_SECTIONcs;inta[5];DWORDWINAPIThread(PVOIDpParams){

inti,num=0;

while(TRUE)

{

EnterCriticalSection(&cs);

for(i=0;i<5;i++)

a[i]=num;

LeaveCriticalSection(&cs);

num++;

}

return0;

}临界区intmain(){

InitializeCriticalSection(&cs);

CreateThread(NULL,0,Thread,NULL,0,NULL);

while(TRUE)

{

EnterCriticalSection(&cs);

printf("%d%d%d%d%d\n",a[0],a[1],a[2],a[3],a[4]);

LeaveCriticalSection(&cs);

}

return0;}临界区#include<windows.h>HANDLEhMutex;inta[5];DWORDWINAPIThread(PVOIDpParams)

{

inti,num=0;

while(TRUE)

{

WaitForSingleObject(hMutex,INFINITE);

for(i=0;i<5;i++)

a[i]=num;

ReleaseMutex(hMutex);

num++;

}

return0;

}互斥量intmain(){

hMutex=CreateMutex(NULL,FALSE,NULL);

CreateThread(NULL,0,Thread,NULL,0,NULL);

while(TRUE)

{

WaitForSingleObject(hMutex,INFINITE);

printf("%d%d%d%d%d\n",a[0],a[1],a[2],a[3],a[4]);

ReleaseMutex(hMutex);

}

return0;}互斥量#include<windows.h>HANDLEhEvent1,hEvent2;inta[5];DWORDWINAPIThread(PVOIDpParams)

{

inti,num=0;

while(TRUE)

{

WaitForSingleObject(hEvent2,INFINITE);

for(i=0;i<5;i++)

a[i]=num;

SetEvent(hEvent1);

num++;

}

return0;

}事件intmain(){

hEvent1=CreateEvent(NULL,FALSE,TRUE,NULL);

hEvent2=CreateEvent(NULL,FALSE,FALSE,NULL);

CreateThread(NULL,0,Thread,NULL,0,NULL);

while(TRUE)

{

WaitForSingleObject(hEvent1,INFINITE);

printf("%d%d%d%d%d\n",a[0],a[1],a[2],a[3],a[4]);

SetEvent(hEvent2);

}

return0;}事件5、信号量信号量可用于资源管理。信号量是一个内核对象一个使用计数32位整数,最大资源数量32位整数,当前资源数量信号量使用规则:当前资源数量大于0,则等待信号量的线程获得资源继续运行,当前资源数量减1当前资源数量等于0,则等待信号量的线程继续等待,直到有线程释放信号量,使当前资源数量大于0创建信号量3.5信号量HANDLECreateSemaphore(

PSECURITY_ATTRIBUTESpsa,

LONGlInitialCount,//initialcount

LONGlMaximumCount,//maximumcount

PCTSTRpszName//objectname

);为现有的一个已命名信号机对象创建一个新句柄。

3.5信号量HANDLEOpenSemaphore(

DWORDfdwAccess,

BOOLbInheritHandle,//inheritanceoption

PCTSTRpszName//objectname

);SEMAPHORE_ALL_ACCESS要求对信号量的完全访问;SEMAPHORE_MODIFY_STATE允许使用ReleaseSemaphore函数;SYNCHRONIZE允许使用信号量同步。释放信号量ReleaseSemaphore(

HANDLEhSem,

LONGlReleaseCount,

PLONGplPreviousCount

);3.5信号量等待信号量DWORDWaitForSingleObject(

HANDLEhHandle,

DWORDdwMilliseconds

);例两个线程分别有一个初值为0的int局部变量,两个线程的行为是在一个循环中,使整型变量递增一个约束条件,在递增过程中,这两个值的差不超过5HANDLEhsem1=CreateSemaphore(NULL,5,10,"sem1");HANDLEhsem2=CreateSemaphore(NULL,5,10,"sem2");inti1=0;inti2=0;DWORDWINAPIThreadFunc1(PVOIDparam){ for(inti=1;i<=100;i++) { WaitForSingleObject(hsem1,INFINITE); ReleaseSemaphore(hsem2,1,NULL); i1++; file<<"i1="<<i1<<"i2="<<i2<<endl; } return0;}DWORDWINAPIThreadFunc2(PVOIDparam){ for(inti=1;i<=100;i++) { WaitForSingleObject(hsem2,INFINITE); ReleaseSemaphore(hsem1,1,NULL); i2++; file<<"i1="<<i1<<"i2="<<i2<<endl; } return0;}生产者/消费者有一个生产者进程,有两个消费者进程。生产者产生1-100的100个数。两个消费者从共享内存中取数。#include<windows.h>intarray[5];//作为仓库存放数据,最多可以放五个数据intpointer;//记录生成数据的个数intpointerget;//记录取得的数据的位置intsum;//用来保存数据和CRITICAL_SECTIONcsArray;//临界区对象HANDLEhFull;//句柄,保存Full信号量HANDLEhEmpty;//句柄,保存Empty信号量//生产者函数DWORDWINAPIProducer(PVOIDpParam){

inti=0;

pointer=0;

while(i<100)

{

WaitForSingleObject(hEmpty,INFINITE);

EnterCriticalSection(&csArray);

array[(pointer++)%5]=i+1;

LeaveCriticalSection(&csArray);

ReleaseSemaphore(hFull,1,NULL);

i++;

}

return0;}//消费者函数ADWORDWINAPIConsumerA(LPVOIDlpParam){

while(1)

{

WaitForSingleObject(hFull,INFINITE);

EnterCriticalSection(&csArray);

sum+=array[(pointerget++)%5];printf("ConsumerAget%d\n",array[(pointerget-1)%5]);

if(pointerget==100)

printf("Thesumis%d",sum);

LeaveCriticalSection(&csArray);

ReleaseSemaphore(hEmpty,1,NULL);

}

return0;}//消费者函数BDWORDWINAPIConsumerB(LPVOIDlpParam){

while(1)

{

WaitForSingleObject(hFull,INFINITE);

EnterCriticalSection(&csArray);

sum+=array[(pointerget++)%5];printf("ConsumerBget%d\n",array[(pointerget-1)%5]);

if(pointerget==100)

printf("Thesumis%d",sum);

LeaveCriticalSection(&csArray);

ReleaseSemaphore(hEmpty,1,NULL);

}

return0;}voidmain(){

HANDLEhThreadProducer,hThreadConsumerA,hThreadComsumerB;

sum=0;

pointerget=0;

InitializeCriticalSection(&csArray);

hFull=CreateSemaphore(NULL,0,5,NULL);

hEmpty=CreateSemaphore(NULL,5,5,NULL);

hThreadProducer=CreateThread(NULL,0,Producer,NULL,0,NULL);

hThreadConsumerA=CreateThread(NULL,0,ConsumerA,NULL,0,NULL);

hThreadComsumerB=CreateThread(NULL,0,

ConsumerB,NULL,0,NULL);

getchar();}哲学家吃饭问题设有5个哲学家,共享一张放有5把椅子的桌子,每人分得一把椅子,但是,桌子上共有5只筷子,在每人两边各放一只,哲学家们在肚子饥饿时才试图分两次从两边拿起筷子就餐。条件:

1)拿到两只筷子时哲学家才开始吃饭。

2)如果筷子已在他人手上,则该哲学家必须等他人吃完之后才能拿到筷子。

3)任一哲学家在自己未拿到两只筷子前却不放下自己手中的筷子。#include<windows.h>constintPHILOSOPHERS=5;//哲学家人数constintTIME_EATING=50;//吃饭需要的时间毫秒HANDLEevent[PHILOSOPHERS];//主线程同工作线程保持同步的句柄数组HANDLEmutex[PHILOSOPHERS];//mutex数组,这里相当于公共资源筷子CRITICAL_SECTIONcs;//控制打印的临界区变量DWORDWINAPIThreadFunc(PVOIDarg){

intnum=*((int*)arg);DWORDret=0;

while(1)

{

ret=WaitForMultipleObjects(2,mutex,TRUE,1000);

if(ret==WAIT_TIMEOUT)

{

Sleep(100);

continue;}

EnterCriticalSection(&cs);

printf("philo

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论