zoukankan      html  css  js  c++  java
  • 第七十六课、多线程间的互斥(下)------------------狄泰软件学院

    一、多线程间的互斥

    1、程序的临界资源与线程锁的数量关系

    (1)、一般性原则:每一个临界资源都需要一个线程锁进行保护

     2、死锁的概念

    (1)、线程间相互等待资源而造成彼此无法继承执行

    3、发生死锁的条件

    (1)、系统中存在多个临界资源且临界资源不可抢占(每次只有一个线程使用)

    (2)、线程需要多个临界资源才能继续执行

    #include <QCoreApplication>
    #include <QThread>
    #include <QMutex>
    #include <QDebug>
    
    static QMutex g_mutex_1;
    static QMutex g_mutex_2;
    
    class ThreadA : public QThread
    {
    protected:
        void run()
        {
            while(true)
            {
                g_mutex_1.lock();//获取第一把锁后就会去等待第二把锁,但第二把锁可能已经被另一个线程获取,会一直死等
                g_mutex_2.lock();
    
                qDebug() << objectName() << " doing work";
    
    
                g_mutex_2.unlock();
                g_mutex_1.unlock();
            }
        }
    };
    
    class ThreadB : public QThread
    {
    protected:
        void run()
        {
            while(true)
            {
                g_mutex_2.lock();
                g_mutex_1.lock();
    
                qDebug() << objectName() << " doing work";
    
    
                g_mutex_1.unlock();
                g_mutex_2.unlock();
            }
        }
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        ThreadA ta;
        ThreadB tb;
    
        ta.setObjectName("ta");
        tb.setObjectName("tb");
    
        ta.start();
        tb.start();
    
        return a.exec();
    }
    死锁的产生

    4、死锁的避免

    (1)、对所有的临界资源都分配唯一一个序号(r1,r2,r3,...,rn)

    (2)、对应的线程锁也分配同样的序号(m1,m2,m3,..., mn)

    (3)、系统中的每个线程按照严格递增的次序请求资源

    #include <QCoreApplication>
    #include <QThread>
    #include <QMutex>
    #include <QDebug>
    
    static QMutex g_mutex_1;
    static QMutex g_mutex_2;
    
    class ThreadA : public QThread
    {
    protected:
        void run()
        {
            while(true)
            {
                g_mutex_1.lock();
                g_mutex_2.lock();
    
                qDebug() << objectName() << " doing work";
    
    
                g_mutex_2.unlock();
                g_mutex_1.unlock();
            }
        }
    };
    
    class ThreadB : public QThread
    {
    protected:
        void run()
        {
            while(true)
            {
                g_mutex_1.lock();//都是递增获取资源
                g_mutex_2.lock();
    
                qDebug() << objectName() << " doing work";
    
    
                g_mutex_2.unlock();
                g_mutex_1.unlock();
            }
        }
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        ThreadA ta;
        ThreadB tb;
    
        ta.setObjectName("ta");
        tb.setObjectName("tb");
    
        ta.start();
        tb.start();
    
        return a.exec();
    }
    改进:都是递增获取临界资源

    5、信号量的概念

    (1)、信号量是特殊的线程锁

    (2)、信号量允许多个线程同时访问临界资源

    (3)、Qt中直接支持信号量(QSemaphore)

     

    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    #include <QSemaphore>
    
    const int SIZE = 5;
    unsigned char g_buff[SIZE] = {0};
    QSemaphore g_sem_free(SIZE);
    QSemaphore g_sem_used(0);
    
    class Producer : public QThread
    {
    protected:
        void run()
        {
            while(true)
            {
                int value = qrand() % 256;
    
                g_sem_free.acquire();//生产了一个产品,需要生产的数量减1
    
                for(int i=0; i<SIZE; i++)
                {
                    if( !g_buff[i] )
                    {
                        g_buff[i] = value;
    
                        qDebug() << objectName() << " generate: {" << i << ", " << value << "}";
    
                        break;
                    }
                }
    
                g_sem_used.release();//生产了一个产品,可用的产品就增1
                sleep(1);
    
            }
        }
    };
    
    class Customer : public QThread
    {
    protected:
        void run()
        {
            while(true)
            {
    
                g_sem_used.acquire();//消费了一个产品,可消费的产品就减1
    
                for(int i=0; i<SIZE; i++)
                {
                    if( g_buff[i] )
                    {
                        int value = g_buff[i];
    
                        g_buff[i] = 0;
    
                        qDebug() << objectName() << " generate: {" << i << ", " << value << "}";
    
                        break;
                    }
                }
    
                g_sem_free.release();//消费了一个产品,所需要生产的产品就增1
                sleep(2);
            }
        }
    };
    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        Producer p1;
        Producer p2;
        Producer p3;
    
        p1.setObjectName("p1");
        p2.setObjectName("p2");
        p3.setObjectName("p3");
    
        Customer c1;
        Customer c2;
    
        c1.setObjectName("c1");
        c2.setObjectName("c2");
    
        p1.start();
        p2.start();
        p3.start();
    
        c1.start();
        c2.start();
    
        return a.exec();
    }
    使用信号量解决多个生产消费者的问题

    二、小结

    (1)、多线程间相互等待资源导致死锁

    (2)、可以对临界资源进行编号的方法避免死锁

    (3)、所有线程必须按照严格递增的次序请求资源

    (4)、Qt中直接支持信号量(QSemaphore)

    (5)、信号量允许多个线程同时访问临界资源

  • 相关阅读:
    location.href使用方法总结
    Ubuntu 12.04 安装JDK 8和Eclipse
    【一】仿微信飞机大战cocos2d-x3.0rc1
    QTP的基本功能介绍
    Spring+Ibatis集成开发实例
    Java NIO与IO的差别和比較
    嵌入式Linux常见问题
    递归和迭代之间的差
    大约sources.list和apt-get [转载]
    JVM学习笔记(一)------的基本结构
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6444087.html
Copyright © 2011-2022 走看看