OpenThreads库的使用-Mutex

Mutex是什么

Mutex,叫互斥锁。
在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

为什么使用Mutex

因为线程存在并发性,并发容易导致问题。举个例子:A,B两个售票员,看到最后还有一张车票。同时,正好有C,D两个人要买这张车票。那么这个车票怎么卖?A认为可以卖给C,B认为可以卖给D。但是最后如果C,D同时买到这张车票,那么谁来坐这个车票的座位呢?
看看程序中的例子。假设有1000张车票,分别由ticketSellThread1和ticketSellThread2来进行销售。

#include <OpenThreads/Thread>
#include <iostream>

int g_ticketCounts = 1000;

class TicketSellThread : public OpenThreads::Thread
{
public:
    virtual void run()
    {
        for (int i = 0; i < 500; i++)
        {
            g_ticketCounts--;
            std::cout << g_ticketCounts << std::endl;
        }
    }
};


int main(int argc, char** argv)
{
    TicketSellThread ticketSellThread1;
    ticketSellThread1.start();

    TicketSellThread ticketSellThread2;
    ticketSellThread2.start();

    //等待ticketSellThread1运行完
    while(ticketSellThread1.isRunning())
        OpenThreads::Thread::YieldCurrentThread();

    //等待ticketSellThread1运行完
    while(ticketSellThread2.isRunning())
        OpenThreads::Thread::YieldCurrentThread();

    return 0;
}

每个线程分别销售500张。那么到最后,这个车票数量应该为0。但是实际情况呢?
这里写图片描述
实际最后还剩下12张。你们的电脑上可能情况不一样,但是最终结果,为一个随机值,很大可能不为0。这是怎么回事?ticketSellThread1和ticketSellThread2都卖了500张,但是最后还剩12张。这中间肯定出现了一张票,卖给2个人的情况。这里,有12张票卖重复了。
那怎么避免这种情况呢?我要保证,一张票,在同一个时间点,只有一个售票员卖。可以这样,A售票员在卖出88号票之前,先给88号票上一把锁。然后B售票员,看到这个88号票,上锁了,就不卖88号票了。
程序中,上锁的方式,有好几种。使用Mutex是其中一种方式。

如何使用Mutex

Mutex的使用,也比较简单。定义一个Mutex,然后使用lock函数,进行上锁,使用unlock函数,进行解锁。下面程序,在g_ticketCounts–之前,对g_ticketCounts进行上锁,然后减完之后,进行解锁。最后运行结果,g_ticketCounts为0,表示所有票正好卖完,没有重复的了。

#include <OpenThreads/Thread>
#include <OpenThreads/Mutex>
#include <iostream>

int g_ticketCounts = 1000;
OpenThreads::Mutex g_ticketMutex;

class TicketSellThread : public OpenThreads::Thread
{
public:
    virtual void run()
    {
        for (int i = 0; i < 500; i++)
        {
            g_ticketMutex.lock();
            g_ticketCounts--;
            g_ticketMutex.unlock();
            std::cout << g_ticketCounts << std::endl;
        }
    }
};


int main(int argc, char** argv)
{
    TicketSellThread ticketSellThread1;
    ticketSellThread1.start();

    TicketSellThread ticketSellThread2;
    ticketSellThread2.start();

    //等待ticketSellThread1运行完
    while(ticketSellThread1.isRunning())
        OpenThreads::Thread::YieldCurrentThread();

    //等待ticketSellThread1运行完
    while(ticketSellThread2.isRunning())
        OpenThreads::Thread::YieldCurrentThread();

    return 0;
}

这里写图片描述

但是Mutex的使用,一定要记得解锁,否则会引起各种问题。
比如下面的代码,当i==5时,我在lock和unlock之间,抛出一个异常,导致线程终止,mutex一直没有执行unlock,一直处于锁住状态。程序没法继续运行。

    virtual void run()
    {
        for (int i = 0; i < 500; i++)
        {
            g_ticketMutex.lock();
            g_ticketCounts--;
            if (i == 5)
            {
                throw std::exception();
            }
            g_ticketMutex.unlock();
            std::cout << g_ticketCounts << std::endl;
        }
    }

这种情况怎么办呢?OpenThreads提供了一个叫做范围锁的东西,ScopedLock。这个类的功能,其实很简单,在它的构造函数中,调用mutex的lock函数,在析构函数中,调用mutex的unlock函数。这样就可以确保mutex的unlock被执行,无论发生了什么。

    virtual void run()
    {
        for (int i = 0; i < 500; i++)
        {
            OpenThreads::ScopedLock<OpenThreads::Mutex> mutloc(g_ticketMutex);
            g_ticketCounts--;
            if (i == 5)
            {
                throw std::exception();
            }
            std::cout << g_ticketCounts << std::endl;
        }
    }

对应的头文件包含为#include <OpenThreads/ScopedLock>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值