windows下多线程同步

互斥量(锁)

适用范围:可以跨进程同步,还可以用来保证程序只有一个互斥锁实例运行(创建命名互斥量),也可以用来做线程间的同步

如果用于进程间同步,一个线程创建互斥量对象后,另一个进程只需要获取互斥量就可以,可以用OpenMutex(MUTEX_ALL_ACCESS,FALSE,"TesthMutex")函数获取

#include<Windows.h>
#include<iostream>
using namespace std;


int money=0;
HANDLE hMutex;
//线程1回调函数
//希望两个线程把monery加到100,线程1休眠的时候让线程2去处理
DWORD WINAPI  ThreadFun1(LPVOID args)
{
	while(true)
	{
		/*
		*检测hHandle事件的信号状态函数详细说明
		*DWORD WINAPI WaitForSingleObject(
		__in HANDLE hHandle,
		__in DWORD dwMilliseconds
		);
		*返回值:执行成功,返回值指示出引发函数返回的事件。它可能为以下值:
		 WAIT_OBJECT_0 0x00000000 :指定的对象出有有信号状态
		 WAIT_TIMEOUT 0x00000102:等待超时
		 WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码
		*参数说明:
		*hHandle	对象句柄,可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等
		*dwMilliseconds]定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了\
		 如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回
		*/

		//等待互斥对象的信号,INFINITE表示一直等待,对之后的代码进行保护,有信号立即返回
		WaitForSingleObject(hMutex,INFINITE);
		if(money<100)
		{
			++money;
			cout<<"thred1 money:"<<money<<endl;
			ReleaseMutex(hMutex);//释放指定互斥对象的所有权,互斥对象变为已通知状态,线程2就能获取到互斥对象
		}
		else
		{
			break;
		}
		
	}
	return 0;
}


//线程2回调函数
DWORD WINAPI  ThreadFun2(LPVOID args)
{
	while(true)
	{
		WaitForSingleObject(hMutex,INFINITE);
		Sleep(1);
		if(money<100)
		{
			++money;
			cout<<"thred2 money:"<<money<<endl;
			ReleaseMutex(hMutex);
		}
		else
		{
			break;
		}
		
	}
	return 0;
}


	
int main()
{
	HANDLE Thread1,Thread2;
	/*
	创建线程函数详细说明
	*HANDLE WINAPI CreateThread(
	__in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes,
	__in      SIZE_T dwStackSize,
	__in      LPTHREAD_START_ROUTINE lpStartAddress,
	__in_opt __deref __drv_aliasesMem LPVOID lpParameter,
	__in      DWORD dwCreationFlags,
	__out_opt LPDWORD lpThreadId
	);
	*返回值:函数成功,返回线程句柄;函数失败返回false。若不想返回线程ID,设置值为NULL
	*参数说明:
	*lpThreadAttributes	线程安全性,使用缺省安全性,一般缺省null
	*dwStackSize	堆栈大小,0为缺省大小
	*lpStartAddress	线程要执行的函数指针,即入口函数
	*lpParameter	线程参数
	*dwCreationFlags	线程标记,如为0,则创建后立即运行
	*lpThreadId	LPDWORD为返回值类型,一般传递地址去接收线程的标识符,一般设为null
	*/
	Thread1=CreateThread(NULL,0,ThreadFun1,NULL,0,NULL);
	if(Thread1==NULL)
	{
		cout<<"CreateThread1 fail"<<endl;
	}

	Thread2=CreateThread(NULL,0,ThreadFun2,NULL,0,NULL);
	if(Thread2==NULL)
	{
		cout<<"CreateThread2 fail"<<endl;
	}
	CloseHandle(Thread1);//关闭线程句柄,内核对象引用计数器减1,只有内核对象引用为0时才会释放线程内存对象
	CloseHandle(Thread2);
	

	/*
	创建互斥对象函数详细说明
	*HANDLE WINAPI CreateMutexA(
	__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
	__in     BOOL bInitialOwner,
	__in_opt LPCSTR lpName
	);		
	*返回值:如执行成功,就返回互斥体对象的句柄;零表示出错。会设置GetLastError。如果返回的是一个有效句柄,但指定的名字已经存在,GetLastError也会设为ERROR_ALREADY_EXISTS,
	bInitialOwner的值将会被忽略。如果调用者限制了权限,GetLastError将会返回ERROR_ACCESS_DENIED,这个时候应该使用OpenMutex函数。
	*参数说明:
	*lpMutexAttributes	指向安全属性的指针
	*bInitialOwner	初始化互斥对象的所有者
	*lpName	指向互斥对象名的指针,如果填写了就算是创建了一个命名的互斥对象,只能有一个test进程运行
	*/
	hMutex =CreateMutex(NULL,false,"test");     //创建命名互斥对象,且为有信号状态
	if(hMutex)
	{
		if(ERROR_ALREADY_EXISTS==GetLastError())
		{
			cout<<"已经有一个相同应用程序在运行!"<<endl;
			return 0;
		}
	}
	system("pause");
	CloseHandle(hMutex);
	return 0;
}	
	
	

事件对象

适用范围:多用于线程间的通信,可以跨进程同步

#include<Windows.h>
#include<iostream>
using namespace std;


int money=0;
HANDLE hEvent;//定义事件句柄
DWORD WINAPI Thread1(LPVOID lpThreadParameter)
{
	while(true)
	{
		WaitForSingleObject(hEvent,INFINITE);//当线程获取到信号时,操作系统会自动把事件对象设置为无信号因为我CreateEvent函数第二个参数设置为自动的
		Sleep(1);
		if(money<100)
		{
			++money;
			cout<<"thred1 money:"<<money<<endl;
			/*
			*重置事件对象为有信号
			*BOOL SetEvent(HANDLE hEvent);
			*返回值:如果操作成功,则返回非零值,否则为0
			*参数说明:
			*hEvent 设置句柄为有信号
			*/
			SetEvent(hEvent);
		}
		else
		{
			break;
		}

	}
	return 0;
}

DWORD WINAPI Thread2(LPVOID lpThreadParameter)
{
	while(true)
	{
		WaitForSingleObject(hEvent,INFINITE);
		Sleep(1);
		if(money<100)
		{
			++money;
			cout<<"thred2 money:"<<money<<endl;
			SetEvent(hEvent);
		}
		else
		{
			break;
		}

	}
	return 0;
}
int main()
{
	
	HANDLE thred1,thred2;

	thred1=CreateThread(NULL,0,Thread1,NULL,0,NULL);
	if(thred1==NULL)
	{
		cout<<"CreateThread1 fail"<<endl;
	}

	thred2=CreateThread(NULL,0,Thread2,NULL,0,NULL);
	if(thred2==NULL)
	{
		cout<<"CreateThread1 fail"<<endl;
	}

	CloseHandle(thred1);//关闭线程句柄
	CloseHandle(thred2);


	/*
	*创建事件对象
	HANDLE WINAPI CreateEventA(
	__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
	__in     BOOL bManualReset,
	__in     BOOL bInitialState,
	__in_opt LPCSTR lpName
	);
	*返回值:如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。
	如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。
	*参数说明:
	*lpEventAttributes	安全性,采用null默认安全性。
	*bManualReset	(TRUE)人工重置或(FALSE)自动重置事件对象为非信号状态,若设为人工重置,则当事件为有信号状态时,所有等待的线程都变为可调度线程。
	*bInitialState		指定事件对象的初始化状态,TRUE:初始为有信号状态。
	*lpName	事件对象的名字,一般null匿名即可
	*/
	hEvent=CreateEvent(NULL,false,true,NULL);
	if(hEvent==NULL)
	{
		cout<<"CreateEvent fail"<<endl;
	}
	system("pause");
	CloseHandle(hEvent);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值