Qt多线程互斥

目录

一、多线程与临界资源的依赖

现象分析

二、互斥和解决方法

三、QMutex的主要成员函数和使用

四、示例代码

五、小结


一、多线程与临界资源的依赖

除了上一节所说的,多线程在代码执行的时序上会有依赖,那么其他地方是否还有所依赖呢?答案是有的,也就是与临界资源的问题,所谓临界资源是指每次只允许一个线程进行访问(读或写)的资源。

假设两个线程都要访问一个全局变量的临界资源,两个线程谁都不让谁,进行对资源的抢占,发生了竞争,致使读写数据会出现错误,严重的可能还会导致程序运行崩溃,出错的现象谁也说不准,比如以下代码的示例:

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

int g_i_current_data = 0;

class ThreadMutexA : public QThread
{
protected:

    void run()
    {
        qDebug() << objectName() << ": run begin...";

        while( true )
        {
            g_i_current_data++;
            qDebug() << objectName() << ": " << g_i_current_data;
            msleep(1);
        }

        qDebug() << objectName() << ": run end...";
    }
};

class ThreadMutexB : public QThread
{
protected:

    void run()
    {
        qDebug() << objectName() << ": run begin...";

        while( true )
        {
            g_i_current_data--;
            qDebug() << objectName() << ": " << g_i_current_data;
            msleep(1);
        }

        qDebug() << objectName() << ": run end...";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main begin...";

    ThreadMutexA thread_a;
    ThreadMutexB thread_b;

    thread_a.setObjectName("ThreadMutexA");
    thread_b.setObjectName("ThreadMutexB");

    thread_a.start();
    thread_b.start();

    qDebug() << "main end...";

    return a.exec();
}

现象分析

1、现象:这段小示例代码已经经过半小时的测试,幸运的是并没有出现程序崩溃,但是仔细一看,数据的打印是有问题的,我们想让这个全局变量在A线程中加1,在B线程中减1,这明显与我们想法相违背;

2、原因分析:导致这现象的原因是多线程对临界资源的抢占,造成了互斥(竞争)的问题。

二、互斥和解决方法

1、多线程互斥:多线程在同一个时刻都需要访问(读/写)临界资源;

2、解决方案:QMutex类是线程锁类,它可以保证线程间的互斥,利用线程锁可以保证临界资源的安全性。

三、QMutex的主要成员函数和使用

1、void QMutex::lock():(1)当锁空闲时,线程获取锁并继续执行;(2)当锁被获取时,阻塞并等待锁的释放。

2、void QMutex::unlock():释放锁,同一把锁的获取lock()和释放unlock()必须成对出现

3、使用

    QMutex mutex;
    mutex.lock();

    // do something you want

    mutex.unlock();

四、示例代码

将线程锁的概念引入上面的问题当中,并解决问题。

#include <QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QDebug>

int g_i_current_data = 0;
QMutex g_mutex;

class ThreadMutexA : public QThread
{
protected:

    void run()
    {
        qDebug() << objectName() << ": run begin...";

        while( true )
        {
            g_mutex.lock();

            g_i_current_data++;
            qDebug() << objectName() << ": " << g_i_current_data;

            g_mutex.unlock();

            msleep(1);
        }

        qDebug() << objectName() << ": run end...";
    }
};

class ThreadMutexB : public QThread
{
protected:

    void run()
    {
        qDebug() << objectName() << ": run begin...";

        while( true )
        {
            g_mutex.lock();

            g_i_current_data--;
            qDebug() << objectName() << ": " << g_i_current_data;

            g_mutex.unlock();

            msleep(1);
        }

        qDebug() << objectName() << ": run end...";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main begin...";

    ThreadMutexA thread_a;
    ThreadMutexB thread_b;

    thread_a.setObjectName("ThreadMutexA");
    thread_b.setObjectName("ThreadMutexB");

    thread_a.start();
    thread_b.start();

    qDebug() << "main end...";

    return a.exec();
}

五、小结

1、临界资源每次只允许一个线程进行访问(读/写)操作;

2、QMutex线程锁可以保护线程间互斥;

3、线程只有获取锁成功才能去访问临界资源;

4、锁被其他线程获取时,就必须阻塞并等待锁的释放;

5、线程锁的获取和释放必须在同一个线程中成对出现,类似new和delete一样。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值