多线程学到这里,会发现我们一直运行的卖票程序有这么几种情况
1.卖出的票的顺序不是顺序排列的
2.同一张票被多个线程各卖出一次
3.卖出的票数多于原本总票数
4.有一张票没有被卖出
5.卖到某一号的票后又从小号开始卖起(俗称回退)
出现上述问题的原因也简单,是因为多线程直接切换的问题,我觉得在我学到这里的时候,完全充分发挥了想象的作用,举例说明上面的情况
卖出的票的顺序不是顺序排列的:
1号线程进来卖3号票,代表票号的i自加后是3,本来打算卖的,2号线程也进来了,i自加后是4了,2号线程还先卖了,到最后1号线程切回来最后才卖的3号票
同一张票被多个线程各卖出一次:
i是1号票,1号线程进来卖票了,还没对i操作,只是拿到了i当前的值,2号线程也进来了,且拿到了当前i的值(有人会问了,1号线程先进来了,2号线程怎么还先运行了,上一篇讲过线程的运行不可预测性),然后2号卖1号票,然后又进来卖了2号票了,这时候1号线程卖的还是1号票
卖出的票数多于原本总票数:
上面的情况同一张票被多卖出就会票数多于总票数
有一张票没有被卖出:
1号线程进来要卖3号票,ticket++,这条语句汇编里是三条语句,进行完00BB1495的时候,另一个线程进来了,也需要用的是eax,eax里本来是ticket++到3的,然后这另一个线程进来加到4,……3号票就错过了
这里我们知道了,不管多少个线程,寄存器是不变的,线程是以汇编语句为单位的
题外话:任务管理器里面性能可以看到线程数
卖到某一号的票后又从小号开始卖起:
代码里有局部变量i获取全局变量j的值,最后给j赋值i,中间是i++,猜想为什么会有回退现象:1号线程得到i的值,++后是2,2号线程得到i的值是3,然后1号线程++到99,2号线程给j赋值,j又变为3,又从3号票卖到99~~~都是想
今天这里讲两个思想
一、全局资源局部化
这是个技巧,假设一个全局变量cout,我们在线程函数里要得到它在这一次的值,用一个局部变量接收,这样它在怎么改变我们不关心
二、临界区
是一个锁,锁的是放入临界区的资源,同时执行临界区的有且只有一个线程
CRITICAL_SECTION cs-----临界区结构体对象
InitializeCriticalSection(&cs)-----初始化临界区
EnterCriticalSection(&cs)------进入临界区
LeaveCriticalSection(&cs)------离开临界区
DeleteCriticalSection(&cs)----销毁临界区
#include <Windows.h>
#define TICKET 100//总票数
#define PERSON 10//总售票员数
int ticket = -1;//卖出的票号
int moreTicket = 0;//多卖的票数
int array[TICKET] = { 0 };//漏票及漏票的数目、重票的数目
CRITICAL_SECTION cs;------------临界区结构体对象
DWORD WINAPI fun(LPVOID L)
{
EnterCriticalSection(&cs); ------------进入临界区
int iNumber = ticket; -------------全局资源局部化
while(iNumber < TICKET)
{
ticket++; ---------------卖的票号++
LeaveCriticalSection(&cs);---------离开临界区
iNumber = ticket; ----------------------局部变量~没有加入锁里
printf("%d号售票员卖的%d号票\n",L,iNumber); --------------------局部变量~没有加入锁里
array[iNumber]++;----------------------下标是局部变量~没有加入锁里
EnterCriticalSection(&cs);-----------进入临界区
moreTicket++;
}
LeaveCriticalSection(&cs);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&cs);
HANDLE sss[PERSON];
for (int i = 0;i<PERSON;i++)
{
sss[i] = CreateThread(0,0,fun,(LPVOID)i,0,0);
}
WaitForMultipleObjects(5,sss,TRUE,INFINITE);
printf("共计------多卖出票数%d张\n",moreTicket - TICKET);
for (int i = 0; i < TICKET; i++)
{
if (array[i] == 0)
{
printf("%d号票漏卖了!\n",i+1);
}
if (array[i] > 1)
{
printf("------%d号票多卖了%d次!\n",i+1,array[i]-1);
}
}
DeleteCriticalSection(&cs);
for (;;);
return 0;
}