用信号量实现线程同步与互斥

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

用信号量实现线程同步与互斥一、相关Win32API函数1、创建线程HANDLECreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,DWORDdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);函数作用:在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。各参数含义:lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,该结构决定了线程的安全属性,一般置为NULL;dwStackSize:指定了线程的堆栈深度,一般都设置为0;lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc是线程函数名;函数名称没有限制,但是必须以下列形式声明:DWORDWINAPIThreadProc(PVOIDpParam);lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;lpThreadId:该参数返回所创建线程的ID。如果创建成功则返回线程的句柄,否则返回NULL。例如:for(inti=0;iPRODUCERS_COUNT;++i){hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);if(hThreads[i]==NULL)return-1;}2、挂起线程DWORDSuspendThread(HANDLEhThread);该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。3、唤醒线程DWORDResumeThread(HANDLEhThread);该函数用于结束线程的挂起状态,执行线程。4、终止线程VOIDExitThread(DWORDdwExitCode);该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。5、创建互斥体HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,BOOLbInitialOwner,LPCTSTRlpName);各参数含义:lpMutexAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承。bInitialOwner:布尔类型,决定互斥体的创建者是否为拥有者。创建进程希望立即拥有互斥体,则设为TRUE,否则设为FALSE。lpName:指定互斥体对象的名字。如已经存在拥有这个名字的一个事件,则打开现有的已命名互斥体例如,HANDLEm_hMutex=CreateMutex(NULL,FALSE,Sample07);//检查错误代码if(GetLastError()==ERROR_ALREADY_EXISTS){//如果已有互斥量存在则释放句柄并复位互斥量CloseHandle(m_hMutex);m_hMutex=NULL;//程序退出returnFALSE;}互斥体可用来实现线程的同步或互斥。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。一旦不再需要,注意必须用CloseHandle函数将互斥体句柄关闭。进程中止前,一定要释放互斥体,如不慎未采取这个措施,就会将这个互斥体标记为废弃,并自动释放所有权。共享这个互斥体的其他应用程序也许仍然能够用它,但会接收到一个废弃状态信息,指出上一个所有进程未能正常关闭。6、释放互斥体BOOLWinAPIReleaseMutex(HANDLEhMutex);hMutex:要释放的互斥体句柄。返回值0代表失败;非0代表成功。7、创建信号量HANDLECreateSemaphore(LPSECURITY_ATTRIBUTESlpSemaphoreAttributes,//SDLONGlInitialCount,//initialcountLONGlMaximumCount,//maximumcountLPCTSTRlpName//objectname);各参数含义:lpSemaphoreAttributes:指定一个SECURITY_ATTRIBUTES结构,或传递零值。该参数定义了信号机的安全特性。lInitialCountLong,设置信号量的初始值。可设置零到lMaximumCount之间的一个值。lMaximumCountLong,设置信号量的最大计数lpNameString,指定信号量对象的名称。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。NULL表示创建匿名信号量。例如,电脑有两个COMPORT,所以只允许两个计数值同时使用COMPORT,因此,hSema=CreateSemaphore(NULL,2,2,MySema)8、释放信号量BOOLReleaseSemaphore(HANDLEhSemaphore,LONGlReleaseCount,LPLONGlpPreviousCount);各参数含义:hSemaphore:信号量句柄lpReleaseCount:表示要增加的数值,lpPreviousCount:用于返回之前的计算值,如果不需要可以设置为NULL。比如我们要控制到服务器的连接数不超过10个,可以创建一个Semaphore,初值为10,每当要连接到服务器时,使用WaitForSingleObject请求Semaphore,当成功返回后再尝试连接到服务器,当连接失败或连接使用完后释放时,调用ReleaseSemaphore增加Semaphore计数值。9、检测信号状态DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds)参数含义:hHandle:是一个事件的句柄。参在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。dwMilliseconds是时间间隔。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。;返回值含义:WAIT_ABANDONED0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。WAIT_OBJECT_00x00000000:核心对象已被激活WAIT_TIMEOUT0x00000102:等待超时WAIT_FAILED0xFFFFFFFF:出现错误,可通过GetLastError得到错误代码二、实例问题描述:有一个文件P被多个进程共享,现在把这些进程分成A、B两组,规定同组进程可以同时读文件P,但当一组进程在读文件P时,不允许另外一组去读文件。用信号量模拟两组进程的读操作。伪代码:SemaphoreS1=1,S2=1,mutex=1;Intnum1=0,num2=0;Process_A(){P(S1);num1++;if(num1==1)thenP(mutex);V(S1);读文件P;P(S1);num1--;if(num1==0)thenV(mutex);V(S1);}Process_B(){P(S2);num2++;if(num2==1)thenP(mutex);V(S2);读文件P;P(S2);num2--;if(num2==0)thenV(mutex);V(S2);}实现代码:#includewindows.h#includeiostreamusingnamespacestd;boolg_continue=true;//控制程序结束intg_Anum=0,g_Bnum=0;//同组用于互斥访问文件,本不应该用这个互斥信号量,只是为了能看清楚输出结果。HANDLEg_hMutexRead;HANDLEg_hMutex;//用于A,B两组互斥访问文件HANDLEg_hA;//用于A组进程互斥访问计数器HANDLEg_hB;//用于B组进程互斥访问计数器voidread();//模拟读DWORDWINAPIProcess_A(LPVOID);//A组线程DWORDWINAPIProcess_B(LPVOID);//B组线程intmain(){//创建互斥访问文件的信号g_hMutexRead=CreateMutex(NULL,FALSE,NULL);g_hMutex=CreateMutex(NULL,FALSE,NULL);g_hA=CreateMutex(NULL,FALSE,NULL);g_hB=CreateMutex(NULL,FALSE,NULL);constunsignedshortA_COUNT=3;//A组线程的个数constunsignedshortB_COUNT=2;//B组线程的个数//总的线程数constunsignedshortTHREADS_COUNT=A_COUNT+B_COUNT;HANDLEhThreads[THREADS_COUNT];//各线程的handleDWORDAID[A_COUNT];DWORDBID[B_COUNT];//创建THREADS_COUNT个线程,读或写线程间隔开intk=0,j=0;for(inti=0;iTHREADS_COUNT;++i){if(i%2==0)//i为偶数时,创建A组线程{hThreads[i]=CreateThread(NULL,0,Process_A,NULL,0,&AID[k]);k++;if(hThreads[i]==NULL)return-1;}else//i为奇数时,创建B组线程{hThreads[i]=CreateThread(NULL,0,Process_B,NULL,0,&BID[j]);j++;if(hThreads[i]==NULL)return-1;}}while(g_continue){if(getchar()){//按回车后终止程序运行g_continue=false;}}return0;}DWORDWINAPIProcess_A(LPVOIDlpPara){/*P(S1);num1++;if(num1==1)thenP(mutex);V(S1);读文件P;P(S1);num1--;if(num1==0)thenV(mutex);V(S1);*/WaitForSingleObject(g_hA,INFINITE);g_Anum++;if(g_Anum==1){WaitForSingleObject(g_hMutex,INFINITE);printf(A组的第一个线程来了,ID=%ld\n,GetCurrentThreadId());}elseprintf(A组又来一个线程,ID=%ld\n,GetCurrentThreadId());ReleaseMutex(g_hA);//模拟读。为了能看清楚输出结果,故同组

1 / 8
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功