多线程同步的四种方式——临界区(线程死锁)

问题的引入:模仿12306多人同时抢票。

解决方法:使用临界区对象。

临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。它并不是核心对象,不是属于操作系统维护的,而是属于进程维护的。

临界区(关键代码段)用到的四个函数:

//初始化临界区对象
void InitializeCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 

//释放临界区对象拥有的资源
void DeleteCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 

//等待指定临界区对象的拥有权
void EnterCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 

//释放指定临界区对象的拥有权
void LeaveCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 

代码实现(本地发现有问题,打印出来的结果只有线程1在运行

#include 	//需要调用windows Api
#include 
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParamter);
DWORD WINAPI Fun2Proc(LPVOID lpParamter);
 
CRITICAL_SECTION g_cs;
int nTickets = 100;	//总票数
int main()
{
	HANDLE hThred1, hThred2;
	hThred1 = CreateThread(NULL, 0, Fun1Proc,
		NULL, 0, NULL);
	hThred2 = CreateThread(NULL, 0, Fun2Proc,
		NULL, 0, NULL);
	CloseHandle(hThred1);
	CloseHandle(hThred2);

	InitializeCriticalSection(&g_cs);	//初始化临界区对象
	Sleep(4000);
	DeleteCriticalSection(&g_cs);	//释放临界区对象拥有的资源
	return 0;
}
 
DWORD WINAPI Fun1Proc(LPVOID lpParamter)
{
	while (TRUE)
	{
		EnterCriticalSection(&g_cs);	//等待指定临界区对象的拥有权
		if (nTickets > 0)
		{
			Sleep(10);
			cout << "thread1 sell ticket:" << nTickets-- << endl;
			LeaveCriticalSection(&g_cs);  
		}
		else
		{
			break;
		}
		LeaveCriticalSection(&g_cs);	//释放指定临界区对象的拥有权
	}
	return 0;
}
 
DWORD WINAPI Fun2Proc(LPVOID lpParamter)
{
	while (TRUE)
	{
		EnterCriticalSection(&g_cs);	//等待指定临界区对象的拥有权
		if (nTickets > 0)
		{
			Sleep(10);
			cout << "thread2 sell ticket:" << nTickets-- << endl;
			LeaveCriticalSection(&g_cs);  
		}
		else
		{
			break;
		}
		LeaveCriticalSection(&g_cs);	//释放指定临界区对象的拥有权
	}
	return 0;
}

线程死锁

原因:线程1拥有了临界区对象A,等待临界区对象B的拥有权。线程2拥有了临界区对象B,等待临界区对象A的拥有权。

#include 	//需要调用windows Api
#include 
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParamter);
DWORD WINAPI Fun2Proc(LPVOID lpParamter);
 
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;

int nTickets = 100;	//总票数
int main()
{
	HANDLE hThred1, hThred2;
	hThred1 = CreateThread(NULL, 0, Fun1Proc,
		NULL, 0, NULL);
	hThred2 = CreateThread(NULL, 0, Fun2Proc,
		NULL, 0, NULL);
	CloseHandle(hThred1);
	CloseHandle(hThred2);

	InitializeCriticalSection(&g_csA);	//初始化临界区对象
	InitializeCriticalSection(&g_csB);	//初始化临界区对象
	Sleep(4000);
	DeleteCriticalSection(&g_csA);	//释放临界区对象拥有的资源
	DeleteCriticalSection(&g_csB);	//释放临界区对象拥有的资源
	return 0;
}
 
DWORD WINAPI Fun1Proc(LPVOID lpParamter)
{
	while (TRUE)
	{
		EnterCriticalSection(&g_csA);	//等待指定临界区对象的拥有权
		Sleep(1);
		EnterCriticalSection(&g_csB);	//等待指定临界区对象的拥有权
		if (nTickets > 0)
		{
			Sleep(10);
			cout << "thread1 sell ticket:" << nTickets-- << endl;
			//LeaveCriticalSection(&g_cs);  
		}
		else
		{
			break;
		}
		LeaveCriticalSection(&g_csB);	//释放指定临界区对象的拥有权
		LeaveCriticalSection(&g_csA);	//释放指定临界区对象的拥有权
	}
	return 0;
}
 
DWORD WINAPI Fun2Proc(LPVOID lpParamter)
{
	while (TRUE)
	{
		EnterCriticalSection(&g_csB);	//等待指定临界区对象的拥有权
		Sleep(1);
		EnterCriticalSection(&g_csA);	//等待指定临界区对象的拥有权
		if (nTickets > 0)
		{
			Sleep(10);
			cout << "thread2 sell ticket:" << nTickets-- << endl;
			//LeaveCriticalSection(&g_cs);  
		}
		else
		{
			break;
		}
		LeaveCriticalSection(&g_csA);	//释放指定临界区对象的拥有权
		LeaveCriticalSection(&g_csB);	//释放指定临界区对象的拥有权
	}
	return 0;
}

 

你可能感兴趣的:(多线程)