线程间同步的四大金刚


总是听说多线程程序有多高效,但是他们也都是有阿喀琉斯之踵的,比如多线程同时访问临界代码段时,就会发生问题。

所以才产生了4种线程同步方式,现用代码来说明四种线程同步方式的使用:

使用最简单的“买票”问题,即两个线程同时卖一堆票,用四种方式控制线程的临界代码段。

       临界区CriticalSetion

 通过对多线程的串行化来控制对一段代码的访问操作,速度快,适合对公共数据的访问控制。任意时刻只允许一个线程访问数据。

 

       事件Event

 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作

 

      互斥量Mutex

采用互斥对象机制。能够保证同一时刻,只有一个线程进入到临界代码段中。

主要函数有三个: 

1、创建互斥量

HANDLE WINAPI CreateMutex(
  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,//安全描述
  __in      BOOL bInitialOwner,//当前线程是否拥有该互斥量
  __in_opt  LPCTSTR lpName//互斥量名称
);

 

2、

DWORD WINAPI WaitForSingleObject(
  __in  HANDLE hHandle,//互斥量句柄   
__in  DWORD dwMilliseconds//等待时限,设置为INFINITE时,表示接收到信号前永远不会返回);


 

 

3、释放互斥量

BOOL WINAPI ReleaseMutex(
  __in  HANDLE hMutex
);

释放指定句柄对应的互斥量

 

 

      信号量Semaphore

优点:通过初始化的最大进入线程个数,可以控制进入到代码段的最大线程。

 

主要函数有三个:

1、创建信号量:

CreateSemaphore(         
NULL,           // default security attributes        
MAX_SEM_COUNT,  // initial count        
MAX_SEM_COUNT,  // maximum count        
NULL);          // unnamed semaphore

通过设置参数二,来控制信号量初始拥有的资源数目。要设置为大于1小于最大值,才能够在接下来的过程中,用WaitForSingleObject函数来获取到资源。

通过设置参数三,来控制信号量可以允许进入的最大线程数。

 

2、等待信号


DWORD WINAPI WaitForSingleObject(
  __in  HANDLE hHandle,//信号量
   __in  DWORD dwMilliseconds//等待时限,设置为INFINITE时,表示接收到信号前永远不会返回
);

当信号量对象中资源计数大于零时,就会返回WAIT_OBJECT_0,并且同时将信号量中的资源计数减少1。

当信号量对象中资源计数等于零时,就会一直等待,获得当超过设置的等待时限后,就会返回WAIT_TIMEOUT。


3、释放信号

BOOL WINAPI ReleaseSemaphore(
  __in       HANDLE hSemaphore,//信号量句柄
  __in       LONG lReleaseCount,//释放信号量对象中多少个信号
  __out_opt  LPLONG lpPreviousCount//释放前信号量对象中拥有的信号量
);

增加信号量中的资源计数。

 

代码如下: 


// test_ThreadSync.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>

/*
同步数据
*/
static int iTicketsNum = 100;

/*
Critical Section 临界区
*/
CRITICAL_SECTION CriticalSection;
short CriticalSectionTest(HANDLE * hThreads);
DWORD WINAPI ThdCriticalSectionA( LPVOID lPvoid );
DWORD WINAPI ThdCriticalSectionB( LPVOID lPvoid );

/*
Event 事件
*/
HANDLE g_Event;
short EventTest(HANDLE * hThreads);
DWORD WINAPI ThdEventA( LPVOID lPvoid );
DWORD WINAPI ThdEventB( LPVOID lPvoid );


/*
Mutex 互斥量
*/
HANDLE g_Mutex;
short MutexTest(HANDLE * hThreads);
DWORD WINAPI ThdMutexA( LPVOID lPvoid );
DWORD WINAPI ThdMutexB( LPVOID lPvoid );

/*
Semaphore 信号量
*/
HANDLE g_Semaphore;
short SemaphoreTest(HANDLE * hThreads);
DWORD WINAPI ThdSemaphoreA( LPVOID lPvoid );
DWORD WINAPI ThdSemaphoreB( LPVOID lPvoid );

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hThreads[2];
	while (1)
	{
		short shRtn = 0;
		printf("选择需要演示的同步方式:\r\n");
		printf("1、CriticalSetion	临界区\r\n");
		printf("2、Event	事件\r\n");
		printf("3、Mutex	互斥量\r\n");
		printf("4、Semaphore	信号量\r\n");

		scanf( "%d" , &shRtn );
		switch(shRtn)
		{
		case 1:
			CriticalSectionTest(hThreads);
			break;
		case 2:
			EventTest(hThreads);
			break;
		case 3:
			MutexTest(hThreads);
			break;
		case 4:
			SemaphoreTest(hThreads);
			break;
		default:
			break;
		}
		::WaitForMultipleObjects( 2 , hThreads , TRUE , INFINITE );
		CloseHandle(hThreads[0]);
		CloseHandle(hThreads[1]);
	}
	return 0;
}

//CriticalSetion 临界区
short CriticalSectionTest(HANDLE * hThreads)
{
	hThreads[0] = ::CreateThread( NULL , 0 , ThdCriticalSectionA , NULL , CREATE_SUSPENDED , NULL);
	hThreads[1] = ::CreateThread( NULL , 0 , ThdCriticalSectionB , NULL , CREATE_SUSPENDED , NULL);
	InitializeCriticalSection(&CriticalSection);

	ResumeThread( hThreads[0] );
	ResumeThread( hThreads[1] );

	return 1;
}

DWORD WINAPI ThdCriticalSectionA( LPVOID lPvoid )
{
	while ( iTicketsNum > 0 )
	{
		EnterCriticalSection(&CriticalSection);
		printf("AThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum-- );
		LeaveCriticalSection(&CriticalSection);
		Sleep(1);
	}
	return 1;
}

DWORD WINAPI ThdCriticalSectionB( LPVOID lPvoid )
{
	while ( iTicketsNum > 0 )
	{
		EnterCriticalSection(&CriticalSection);
		printf("BThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
		LeaveCriticalSection(&CriticalSection);
		Sleep(1);
	}
	return 1;
}

short EventTest(HANDLE * hThreads)
{
	hThreads[0] = ::CreateThread( NULL , 0 , ThdEventA , NULL , CREATE_SUSPENDED , NULL);
	hThreads[1] = ::CreateThread( NULL , 0 , ThdEventB , NULL , CREATE_SUSPENDED , NULL);

	//初始化event
	g_Event  = ::CreateEvent( NULL , TRUE , FALSE , NULL );
	::SetEvent(g_Event);

	ResumeThread( hThreads[0] );
	ResumeThread( hThreads[1] );
	return 1;
}
DWORD WINAPI ThdEventA( LPVOID lPvoid )
{
	while( iTicketsNum > 0)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject( g_Event , INFINITE ))
		{
			printf("AThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
			::SetEvent(g_Event);
			Sleep(1);
		}
	}
	return 1;
}
DWORD WINAPI ThdEventB( LPVOID lPvoid )
{
	while( iTicketsNum > 0)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject( g_Event , INFINITE ))
		{
			printf("BThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
			::SetEvent(g_Event);
			Sleep(1);
		}
	}
	return 1;
}


short MutexTest(HANDLE * hThreads)
{
	hThreads[0] = ::CreateThread( NULL , 0 , ThdMutexA , NULL , CREATE_SUSPENDED , NULL);
	hThreads[1] = ::CreateThread( NULL , 0 , ThdMutexB , NULL , CREATE_SUSPENDED , NULL);

	//初始化event
	g_Mutex = ::CreateMutex( NULL , FALSE , NULL );
	if (g_Mutex == NULL)
	{
		CloseHandle(hThreads[0]);
		CloseHandle(hThreads[1]);
		 return 0;
	}

	ResumeThread( hThreads[0] );
	ResumeThread( hThreads[1] );

	return 1;
}
DWORD WINAPI ThdMutexA( LPVOID lPvoid )
{
	while( iTicketsNum > 0)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject( g_Mutex , INFINITE ))
		{
			printf("AThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
			ReleaseMutex( g_Mutex );
			Sleep(1);
		}
	}
	return 1;
}
DWORD WINAPI ThdMutexB( LPVOID lPvoid )
{
	while( iTicketsNum > 0)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject( g_Mutex , INFINITE ))
		{
			printf("BThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
			ReleaseMutex( g_Mutex );
			Sleep(1);
		}
	}
	return 1 ;
}


short SemaphoreTest(HANDLE * hThreads)
{
	hThreads[0] = ::CreateThread( NULL , 0 , ThdSemaphoreA , NULL , CREATE_SUSPENDED , NULL);
	hThreads[1] = ::CreateThread( NULL , 0 , ThdSemaphoreB , NULL , CREATE_SUSPENDED , NULL);

	//初始化event
	g_Semaphore = ::CreateSemaphore( NULL , 1 , 1 , NULL);
	if (g_Semaphore == NULL)
	{
		CloseHandle(hThreads[0]);
		CloseHandle(hThreads[1]);
		return 0;
	}

	ResumeThread( hThreads[0] );
	ResumeThread( hThreads[1] );
	return 1;
}

DWORD WINAPI ThdSemaphoreA( LPVOID lPvoid )
{
	long preNum;
	while( iTicketsNum > 0)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject( g_Semaphore , INFINITE ))
		{
			printf("AThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
			::ReleaseSemaphore(g_Semaphore , 1 , &preNum );
			Sleep(1);
		}
	}
	return 1 ;
}

DWORD WINAPI ThdSemaphoreB( LPVOID lPvoid )
{
	long preNum;
	while( iTicketsNum > 0)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject( g_Semaphore , INFINITE ))
		{
			printf("BThread Seal Ticket , leave %d tickets!\r\n",iTicketsNum--);
			::ReleaseSemaphore(g_Semaphore , 1 , &preNum);
			Sleep(1);
		}
	}
	return 1 ;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值