当前位置:文档之家› 用信号量实现线程同步与互斥

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

int k=0,j=0;
for(int i=0;i<THREADS_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()){ //按回车后终止程序运行
用信号量实现线程同步与互斥
一、相关Win32 API函数
1、创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
4、终止线程
VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
5、创建互斥体
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes,
DWORD WINAPI Process_A(LPVOID); //A组线程
DWORD WINAPI Process_B(LPVOID); //B组线程
int main()
{
//创建互斥访问文件的信号
g_hMutexRead = CreateMutex(NULL,FALSE,NULL);
g_hMutex = CreateMutex(NULL,FALSE,NULL);
//如果已有互斥量存在则释放句柄并复位互斥量
CloseHandle(m_hMutex);
m_hMutex = NULL;
//程序退出
return FALSE;
}
互斥体可用来实现线程的同步或互斥。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
一旦不再需要,注意必须用CloseHandle函数将互斥体句柄关闭。进程中止前,一定要释放互斥体,如不慎未采取这个措施,就会将这个互斥体标记为废弃,并自动释放所有权。共享这个互斥体的其他应用程序也许仍然能够用它,但会接收到一个废弃状态信息,指出上一个所有进程未能正常关闭。
二、实例
问题描述:有一个文件P被多个进程共享,现在把这些进程分成A、B两组,规定同组进程可以同时读文件P,但当一组进程在读文件P时,不允许另外一组去读文件。用信号量模拟两组进程的读操作。
伪代码:
Semaphore S1=1,S2=1,mutex=1;
Int num1=0,num2=0;
Process_A()
dwStackSize:指定了线程的堆栈深度,一般都设置为0;
lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc是线程函数名;函数名称没有限制,但是必须以下列形式声明:DWORD WINAPIThreadProc(PVOID pParam);
读文件P;
P(S2);
num2--;
if(num2==0) then V(mutex);
V(S2);
}
实现代码:
#include <windows.h>
#include <iostream>
using namespace std;
bool g_continue = true; //控制程序结束
int g_Anum=0,g_Bnum=0;
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
函数作用:在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。
各参数含义:
lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,该结构决定了线程的安全属性,一般置为NULL;
lpThreadId:该参数返回所创建线程的ID。
如果创建成功则返回线程的句柄,否则返回NULL。
例如:
for (int i=0;i<PRODUCERS_COUNT;++i){
hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
BOOLbInitialOwner,
LPCTSTRlpName);
各参数含义:
lpMutexAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承。
bInitialOwner:布尔类型,决定互斥体的创建者是否为拥有者。创建进程希望立即拥有互斥体,则设为TRUE,否则设为FALSE。
例如,电脑有两个COM PORT,所以只允许两个计数值同时使用COM PORT,因此,hSema = CreateSemaphore(NULL, 2, 2, "MySema")
8、释放信号量
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
9、检测信号状态
DWORD WaitForSingleObject(
HANDLE hHandle,DW源自RD dwMilliseconds)
参数含义:
hHandle:是一个事件的句柄。参在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。
6、释放互斥体
BOOL WinAPI ReleaseMutex(HANDLE hMutex);
hMutex:要释放的互斥体句柄。返回值0代表失败;非0代表成功。
7、创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD
g_continue = false;
}
}
return 0;
}
DWORD WINAPI Process_A(LPVOID lpPara)
{
/*
P(S1);
num1++;
if(num1==1) then P(mutex);
V(S1);
读文件P;
P(S1);
num1--;
if(num1==0) then V(mutex);
lpName:指定互斥体对象的名字。如已经存在拥有这个名字的一个事件,则打开现有的已命名互斥体
例如,
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
//检查错误代码
if (GetLastError() == ERROR_ALREADY_EXISTS) {
返回值含义:
WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。
WAIT_OBJECT_0 0x00000000:核心对象已被激活
WAIT_TIMEOUT 0x00000102:等待超时
WAIT_FAILED 0xFFFFFFFF:出现错误,可通过GetLastError得到错误代码
LONG lInitialCount, // initial count
LONG lMaximumCount, // maximum count
LPCTSTR lpName // object name);
各参数含义:
lpSemaphoreAttributes:指定一个SECURITY_ATTRIBUTES结构,或传递零值。该参数定义了信号机的安全特性。
//总的线程数
const unsigned short THREADS_COUNT = A_COUNT+B_COUNT;
HANDLE hThreads[THREADS_COUNT]; //各线程的handle
DWORD AID[A_COUNT];
DWORD BID[B_COUNT];
//创建THREADS_COUNT个线程,读或写线程间隔开
dwMilliseconds是时间间隔。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。;
相关主题