-
四种线程同步方式比较
-
代码
/****************使用以下四种方式实现线程同步******************
(1)事件(Event);
(2)信号量(semaphore);
(3)互斥量(mutex);
(4)临界区(Critical section)
**************************************************************/
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI myfun1(LPVOID lpParameter); //声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
/************使用临界区对象实现多线程同步***************
临界区被初始化后,当程序进入临界区后便拥有临界区的所有权,其余线程无权进入只能等对方释放临界区之后,方可进入临界区拥有其所有权再对临界区进行操作
InitializeCriticalSection()初始化临界区;
EnterCriticalSection()进入临界区;
LeaveCriticalSection()释放临界区所有权并离开临界区;
注意:上述是windows API中相关函数,CCriticalSection类是MFC中定义的临界区类,需要在MFC程序中使用(此程序为控制台程序无法使用MFC类),可以操作临界区,lock锁定临界区、unlock释放临界区
临界区为依次访问,不能实现其中一个线程一释放临界区就会被另一个线程访问临界区!不能实现实时监听
********************************************************/
/************使用事件对象实现多线程同步***************
事件对象是指用户在程序中使用内核对象的有无信号状态实现线程的同步临界区被初始化后,当程序进入临界区后便拥有临界区的所有权,其余线程无权进入只能等对方释放临界区之后,方可进入临界区拥有其所有权再对临界区进行操作
CreatEvent()创建并返回事件对象;
SetEvent()将指定的事件设置为有信号状态(有信号状态下其余线程可以访问);
ResetEvent()将指定的事件设置为无信号状态;
除SetEvent函数外,WaitForSingleObject函数等待指定事件。
注意:上述是Windows API函数,CEvent类是MFC实现事件对象的类
事件对象为立即访问,一旦事件对象被设置为有信号 立刻会被其余线程访问!能实现实时监听
********************************************************/
/************使用互斥对象实现多线程同步***************
互斥对象还可以在进程间使用,在实现线程同步时包含一个线程ID和一个计数器,线程ID表示拥有互斥对象的线程,计数器表示该互斥对象被同一线程所使用次数
CreatMutex()创建并返回互斥对象;
ReleaseMutex()释放互斥对象句柄;
WaitForSingleObject()对该对象进行请求。
注意:上述是Windows API函数,CMutex类是MFC中的互斥对象类
互斥对象为立即访问,一旦互斥对象被释放 立刻会被其它正在等待的线程访问!能实现实时监听
********************************************************/
/************使用信号量实现多线程同步***************
CreateSemaphore()创建并返回信号量;
ReleaseSemaphore()释放信号量句柄;
WaitForSingleObject()对该对象进行请求。
********************************************************/
static int a=0;
CRITICAL_SECTION section;//定义临界区对象(Windows API)
HANDLE hevent;//定义全局事件变量句柄
HANDLE hmutex;//定义全局互斥对象句柄
HANDLE hSemaphore; //定义信号量句柄
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h1,h2;//声明句柄变量
//InitializeCriticalSection(§ion);//初始化临界区对象(需要在线程前初始化)
//hevent=CreateEvent(NULL,FALSE,false,NULL);//创建事件并返回句柄
//SetEvent(hevent);//设置事件为有信号状态
//hmutex=CreateMutex(NULL,false,NULL);//创建互斥对象并返回其句柄
hSemaphore = CreateSemaphore(NULL, 1, 100, "sema");//创建信号量
h1=CreateThread(NULL,0,myfun1,NULL,0,NULL);//创建线程1
cout<<"线程1开始运行!\n"<<endl;
h2=CreateThread(NULL,0,myfun2,NULL,0,NULL);//创建线程2
cout<<"线程2开始运行!"<<endl;
//关闭线程句柄对象
CloseHandle(h1);
CloseHandle(h2);
while (1)
{
if (getchar()=='q')//如果用户输入字符q
{
//DeleteCriticalSection(§ion);//删除临界区对象
return 0;//程序正常退出
}
else
{
Sleep(100);//程序睡眠
}
}
return 0;
}
//分别实现线程函数,并返回值
DWORD WINAPI myfun1(LPVOID lpParameter)
{
long count;
while (true)
{
//EnterCriticalSection(§ion); //进入临界区
//WaitForSingleObject(hevent,INFINITE); //使线程进入等待状态,直到事件对象变为已通知状态为止。INFINITE表示永久等待
//ResetEvent(hevent); //设置事件对象为无信号状态
//WaitForSingleObject(hmutex,INFINITE);//使线程进入等待状态,直到互斥对象变为已通知状态为止。INFINITE表示永久等待
WaitForSingleObject(hSemaphore, INFINITE); //等待信号量为有信号状态
a++;
if (a<1000)
{
cout<<"线程1正在计数"<<a<<endl;
//LeaveCriticalSection(§ion);//离开临界区
//SetEvent(hevent);
//ReleaseMutex(hmutex);//释放互斥对象句柄
ReleaseSemaphore(hSemaphore, 1, &count); //释放信号量
}
else
{
//a=0;
//LeaveCriticalSection(§ion);
//SetEvent(hevent);
//ReleaseMutex(hmutex);//释放互斥对象句柄
ReleaseSemaphore(hSemaphore, 1, &count); //释放信号量
break;
}
}
return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter)
{
long count;
while (true)
{
//EnterCriticalSection(§ion);//进入临界区
//WaitForSingleObject(hevent,INFINITE);//请求事件对象
//ResetEvent(hevent);//设置事件对象为无信号状态
//WaitForSingleObject(hmutex,INFINITE);使线程进入等待状态,直到互斥对象变为已通知状态为止。INFINITE表示永久等待
WaitForSingleObject(hSemaphore, INFINITE); //等待信号量为有信号状态
a++;
if (a<1000)
{
cout<<"线程2正在计数"<<a<<endl;
//LeaveCriticalSection(§ion);//离开临界区
//SetEvent(hevent);
//ReleaseMutex(hmutex);//释放互斥对象句柄
ReleaseSemaphore(hSemaphore, 1, &count); //释放信号量
}
else
{
//LeaveCriticalSection(§ion);//离开临界区,当计数a大于1000时退出循环
//SetEvent(hevent);
//ReleaseMutex(hmutex);//释放互斥对象句柄
ReleaseSemaphore(hSemaphore, 1, &count); //释放信号量
break;
}
}
return 0;
}