问题的引入:模仿12306多人同时抢票。
解决方法:使用临界区对象。
临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。它并不是核心对象,不是属于操作系统维护的,而是属于进程维护的。
临界区(关键代码段)用到的四个函数:
//初始化临界区对象
void InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
//释放临界区对象拥有的资源
void DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
//等待指定临界区对象的拥有权
void EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
//释放指定临界区对象的拥有权
void LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
代码实现(本地发现有问题,打印出来的结果只有线程1在运行)
#include <Windows.h> //需要调用windows Api
#include <iostream>
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.h> //需要调用windows Api
#include <iostream>
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;
}