总是听说多线程程序有多高效,但是他们也都是有阿喀琉斯之踵的,比如多线程同时访问临界代码段时,就会发生问题。
所以才产生了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 ;
}