C++晋升之多线程三(解决重票漏票)

多线程学到这里,会发现我们一直运行的卖票程序有这么几种情况

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;
}
    

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值