第75课 多线程间的互斥(上)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第75课 多线程间的互斥(上)相关的知识,希望对你有一定的参考价值。

1. 生产消费者问题

(1)问题描述

  ①有n个生产者同时制造产品,并把产品存入仓库中

  ②有m个消费者同时需要从仓库中取出产品。

(2)规则

  ①当仓库未满,任意生产者可以存入产品。

  ②当仓库未空,任意消费者可以取出产品。

2. 生活中的例子

  ①线程间除了时序上可能存在依赖,还可能读写共享资源时存在依赖

  ②洗手间的使用

技术分享 

  ③“十字路口”

技术分享 

3. 多线程间的互斥

(1)临界资源(Critical Resource):每次只允许一个线程进行访问(读/写)的资源。(注意,这与Windows下的临界区不是一个概念,临界资源是要共享读写的资源)。

(2)线程间的互斥(竞争):多个线程在同一时刻都需要访问临界资源,这时会产生竞争。

(3QMutex类是一把线程锁保证线程间的互斥。利用线程锁能够保证临界资源的安全性。

4. QMutex中的关键成员函数

(1)void lock()函数

  ①当锁空闲时,获取锁并继续执行。

  ②当锁被其他线程占有时,阻塞并等待锁的释放。

(2)void unlock()函数:

  ①释放锁(同一把锁的获取和释放必须在同一线程中成对出现

  ②如果调用unlock()时处于空闲状态,也就是在调用lock()之前先调用unlock(),那么程序的行为是未定义的

【编程实验】解决生产消费者问题

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

#define MAXSTORAGE 10  //最大库存量

static QMutex g_mutex;  //读写库存锁
static QMutex g_debug;  //qdebug锁
static QString g_store;

//生产者
class Producer : public QThread
{
protected:
    void run()
    {
        int count = 0;

        while (true)
        {
            g_mutex.lock();

            //生产数据,未满仓时将数据加入仓库
            if(g_store.count() <= MAXSTORAGE)
            {
                g_store.append(QString::number((count++) % 10));

                g_debug.lock();
                qDebug() << objectName() << ":" + g_store;
                g_debug.unlock();
            }

           g_mutex.unlock();

            msleep(1);
        }
    }
};

//消费者
class Customer : public QThread
{
protected:
    void run()
    {
        while (true)
        {
            g_mutex.lock();

            //仓库
            if(g_store.count() > 0)
            {
                //字符串中的最前面的1个字符
                g_store.remove(0, 1);

                g_debug.lock();
                qDebug() << objectName() << ":" + g_store;
                g_debug.unlock();
            }

            g_mutex.unlock();

            msleep(1);
        }
    }
};

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

    Producer p;
    Customer c;

    p.setObjectName("Producer");
    c.setObjectName("Customer");

    p.start();
    c.start();

    return a.exec();
}

5. 小结

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

(2)线程锁(QMutex)用于保护临界资源

(3)线程只有获取锁之后才能访问临界资源

(4)锁被其他线程获取时,当前线程进入等待状态。

(5)线程锁的获取和释放必须在同一线程中成对出现

 

以上是关于第75课 多线程间的互斥(上)的主要内容,如果未能解决你的问题,请参考以下文章

经典线程同步总结 关键段 事件 互斥量 信号量

多线程(上)

多线程间的互斥(下)

c# 多线程互斥问题。。

操作系统:进程间的相互作用(多线程基础)

多线程互斥锁读写锁