互斥量(锁)
适用范围:可以跨进程同步,还可以用来保证程序只有一个互斥锁实例运行(创建命名互斥量),也可以用来做线程间的同步
如果用于进程间同步,一个线程创建互斥量对象后,另一个进程只需要获取互斥量就可以,可以用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;
}