设为首页 加入收藏

TOP

windows多线程编程星球(一)(五)
2017-10-11 18:24:43 】 浏览:741
Tags:windows 线程 编程 星球
分成两种模式,特权模式和非特权模式,你可以理解为一些非常关键的指令,比如读取或改变诸如程序状态字之类控制寄存器的指令、原始I/O 指令和与内存管理相关的指令等等只能是像操作系统这样级别的总体调度者才能执行,如果谁都能执行,那么操作系统就乱了。这两个另外一个差别是Mutex是可以跨进程使用,而CRITICAL_SECTION肯定是不行的。最后一个我觉得重要的是如果拥有Mutex的线程非法的结束了,那么其状态会变成abandoned状态,这个时候你用WaitForSingleObject依然可以取得这个锁并且做一些工作,而CRITICAL_SECTION只会变成未知状态,你可能能不能再进入资源变成了未知。

          关于Mutex是怎样实现资源的同步与控制的,按理说他也是一条条的指令,为啥它就不能被线程切换打断而SetConsoleCursorPosition就能呢?这里首先要说到的是原子操作,对于原子操作的定义是这样的:如果这个操作所处的层(layer)的更高层不能发现其内部实现与结构。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。简单点的说就是原子操作不同于普通的指令操作,它是不可以被打断的,要么一次性执行完,要么一个也不执行。原子操作的实现是一个很深度也很具有技术难度的问题,具体的有兴趣的话可以查看http://www.cnblogs.com/fanzhidongyzby/p/3654855.html。而对于Mutex对象包含: 一个线程 ID ,使用计数和递归计数 。线程 ID 表示当前占用该互斥量的线程 ID ,递归计数表示该线程占用互斥量的次数,使用计数表示使用互斥量对象的不同线程的个数。通过这三个元素,Mutex才能完成同步与控制。这里还想扯扯的就是CreateMutex的第二个参数,如果第二个参数是ture,那么表示当前创建Mutex的线程拥有该mutex对象,也就是说当前线程先占用了该Mutex对象,在该线程调用ReleaseMutex之前,别的线程是无法通过WaitForSingleObject等待这个Mutex的。而ReleaseMutex的具体作用是每调用它一次将互斥对象的计数器减一,直到减到零为止,此时释放互斥对象,并将互斥对象中的线程id 置零。它的使用条件是,互斥对象在哪个线程中被创建,就在哪个线程里面释放。因为调用的时候会检查当前线程的id是不是与互斥对象中保存的id一致,若一致,则此次操作有效,不一致,则无效。

 

五、命令与控制。

         从前面到这里,planet里面定义的resource属性到现在还没有使用,那么在这一节,我准备使用上这个属性。在我任性的逻辑里面我准备这样做,子星球每前进一步消耗一点资源,然后将这个资源输出在console的屏幕上的某个位置。那末就先构造好这个资源显示函数:

void UpdatePlanetResource(struct Planet &p)
{ 
    char cRes[3];
    itoa(p.resource,cRes,10);

    if( p.type == 1 ) 
    { 
        MoveOutputToPos(2,0,cRes,true); 
    }
    else
    {
        MoveOutputToPos(1,p.index*3,cRes,true);  
    } 
}

        这个函数就是根据不同的星球类型显示目前他的资源数字。在我们的程序中,我们需要时时的更新这些资源数据,那么看起来应该很简单的一个问题,分别在主线程和子线程中相应位置调用这个函数就好了。仔细看一下这个想法,会发现一个问题,在我们的设计中,母星球旋转的速度和子星球前进的速度并不一样,母星球显示刷新周期是80ms而子星球是500ms,也就是说子星球没500ms消耗一点资源而这个时候母星球已经刷新了四个周期了。这样的话会有一个很现实的问题,你无法实现两个资源消耗额度的同步刷新。如果你单纯的只是在两个星球的while循环中调用上面的函数,你会发现两个资源的增加与减少并不同步。这时候会想到有没有一种办法,当子星球消耗了一点资源的时候才去通知母星球,然后让它去更新一下自己的资源?

        为了解决成千上万和这个问题一样的问题,windows多线程编程中提供了一个叫Event的对象来实现这一通知响应机制。要使用Event,首先还得创建一个handle对象作为CreateEvent的返回值,类似于CreateMutex:

         hEvent = CreateEvent( NULL , FALSE , FALSE , NULL );

        相比于CreateMutex函数,CreateEvent有四个参数,第一个和最后一个参数的意义和CreateMutex相同。那么就只需要介绍一下第二个,第三个参数,第二个参数是是否手工设置状态,第三个是Event的初始状态是啥。要具体解释一下这两个参数就要先解释一下Event的状态,和Mutex一样作为一个内核对象,Event也有激活态和非激活态。如果第二个参数是false,那么在每次获得激活状态的Event对象之后,Event对象会自动设置为未激活状态,反之,则需要手工调用ResetEvent将其设置为未激活状态。第三个参数如果是True,那么这个Event的初始状态就是激活的,反之则是未激活的。

        下面我们就要让子星球给母星球发送更新通知了,采用的函数是SetEvent,将event设置为激活状态,相当于给母星球发送一个通知,我们在子星球的PlanetMove里面加入如下代码:

void PlanetMove(struct Planet &p)
{  
    char cLine[100];
    memset(cLine,0,100*sizeof(char)); 

    if( p.resource < nMaxResource-1 ) 
    {
        p.resource++;
        memset(cLine,'-',p.resource*sizeof(char));
        MoveOutputToPos(0,p.index*3+1,cLine,true); 
        
        UpdatePlanetResource(p);
        SetEvent(hEvent);
    }  
}

          在更新resource状态之后将event设置为激活状态,此时母星球线程中的wait函数就会等到这个event

首页 上一页 2 3 4 5 6 下一页 尾页 5/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇win7如何恢复以前的ie版本 下一篇在IE中解决当前安全设置不允许下..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目