第76课 - 多线程间的互斥(下)

版权声明:课程笔记内容整理于狄泰软件 https://blog.csdn.net/qq_39654127/article/details/81949146

1、多线程间的互斥 

一般性原则 

       每一个临界资源都需要一个线程锁进行保护! 

有趣的示例 

                                     都分别试图获取两把线程锁,阻塞其它进程,保护临界资源

2、编程实验 

有趣的示例 76-1.pro 

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

QMutex g_mutex_1;
QMutex g_mutex_2;

class ThreadA : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            g_mutex_1.lock();

            qDebug() << objectName() << "get m1";

            g_mutex_2.lock();

            qDebug() << objectName() << "get m2";

            qDebug() << objectName() << "do work ...";

            g_mutex_2.unlock();
            g_mutex_1.unlock();

            sleep(1);
        }
    }
};

class ThreadB : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            g_mutex_2.lock();

            qDebug() << objectName() << "get m2";

            g_mutex_1.lock();

            qDebug() << objectName() << "get m1";

            qDebug() << objectName() << "do work ...";

            g_mutex_1.unlock();
            g_mutex_2.unlock();

            sleep(1);
        }
    }
};

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();
}

运气好的话某一线程可能完成一次工作

线程的死锁概念 

        -线程间相互等待临界资源而造成彼此无法继续执行 

发生死锁的条件 (满足不一定发生)

        -系统中存在多个临界资源临界资源不可抢占(每次只能给一个线程使用)

        -线程需要多个临界资源才能继续执行 

     

死锁的避免 

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

        -对应的线程锁也分配同样的序号(m1, m2 , mn) 

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

                                针对上面死锁实验只需要将线程B中的锁换一下位置即可

信号量的概念 

        -信号量是特殊的线程锁 

        -信号量允许N个线程同时访问临界资源

        -Qt中直接支持信号量(QSemaphore

QSemaphore使用示例 

          QSemaphore对象中维护了一个整型值 

                ★ acquire()使得该值减1 , release()使得该值加1 

                ★ 当该值为0时,acquire()函数将阻塞当前线程 

3、编程实验 

再论生产消费者问题    76-2.pro 

main.cpp

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QSemaphore>
#include <Qdebug>

const int SIZE = 5;
unsigned char g_buff[SIZE] = {0};//5个仓库

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信号量(整形值)为0,阻塞在这里,不可存
            g_sem_free.acquire();

            for(int i=0; i<SIZE; i++)
            {
                if( !g_buff[i] )
                {
                    g_buff[i] = value;

                    qDebug() << objectName() << " generate: {" << i << ", " << value << "}";

                    break;
                }
            }

            //g_sem_used信号量加1,可取仓库加1
            g_sem_used.release();

            sleep(2);
        }
    }
};

class Customer : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            //若g_sem_used信号量为0,阻塞在这里,不可取
            g_sem_used.acquire();

            for(int i=0; i<SIZE; i++)
            {
                if( g_buff[i] )
                {
                    int value = g_buff[i];

                    g_buff[i] = 0;

                    qDebug() << objectName() << " consume: {" << i << ", " << value << "}";

                    break;
                }
            }

            //g_sem_free信号量加1,可存仓库加1
            g_sem_free.release();

            sleep(1);
        }
    }
};

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();
}

4、小结 

多线程间相互等待临界资源将导致死锁 

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

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

Qt中直接支持信号量(QSemaphore

信号量允许N个线程同时访问临界资源

猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/81949146