qt-线程竞争共享资源和读写锁--QReadWriteLock


一、线程竞争的概念

2、什么是线程竞争

线程竞争指的是在多线程环境下,多个线程同时访问和修改共享资源时可能引发的问题。
当多个线程同时竞争对同一资源进行读写或修改操作时,可能会导致不可预测的结果,包括程序崩溃、数据损坏或逻辑错误等。

线程竞争可能导致的问题包括:

  • 数据竞争:多个线程同时读写共享变量,导致数据的值无法预测或出现错误结果
  • 竞态条件:多个线程执行的顺序和时机不确定,导致最终结果与期望不符。
  • 死锁:多个线程相互等待对方释放资源,导致程序无法继续执行。
  • 活锁:多个线程无法取得进展,每个线程都在不断重试,但无法完成任务。
  • 饥饿:某个线程无法获取到需要的资源,导致一直无法执行。

为了避免线程竞争带来的问题,需要使用适当的同步机制和技术,例如互斥锁、条件变量、原子操作等,来保护共享资源的访问、修改和使用过程。正确地设计和实现多线程编程是确保程序安全性和稳定性的重要一步。

2、什么是线程竞争共享资源?

  • 在线程并发编程中,当多个线程同时访问和修改共享资源时,就会发生线程竞争。
  • 共享资源可以是数据结构、变量、文件或其他可被多个线程访问的对象。

线程竞争共享资源可能会导致以下问题:

  • 数据不一致:当多个线程同时读写共享资源时,它们可能会产生不一致的结果。例如,一个线程正在读取数据,而另一个线程正在同时修改该数据,这可能导致读取到的数据是过时或不正确的。
    一个读取,一个写入

  • 数据丢失:如果多个线程同时写入共享资源,其中一个线程的写入结果可能会被其他线程的写入覆盖,从而导致数据丢失。
    在这里插入图片描述

  • 程序崩溃:线程竞争还可能导致程序崩溃或死锁。当多个线程在访问共享资源时,如果它们无法正确同步和互斥地进行访问,就可能导致死锁情况,其中线程相互等待对方释放资源,从而无法继续执行。

二、读写锁

1、读写锁的概念

  • 读写锁是一种线程同步机制,用于解决多线程环境下的读写竞争问题
  • 读写锁允许多个线程同时获取读锁(共享访问)但只允许一个线程获取写锁(独占访问)
  • 这种机制可以提高并发性能,因为多个线程可以同时读取共享资源而不会相互干扰

2、读写锁的工作原理如下:

  • 当线程希望读取共享资源时,它们可以获取读锁。多个线程可以同时持有读锁,因此它们可以并行地读取共享资源。
    在这里插入图片描述

  • 当线程希望修改(写入)共享资源时,它必须获取写锁。写锁是独占的,即只允许一个线程持有写锁,其他线程无法获取读锁或写锁。这确保了在写入操作期间的独占访问,防止其他线程同时读取或写入共享资源

  • 当一个线程持有写锁时,其他线程的读锁和写锁请求会被阻塞,直到写锁被释放。
    在这里插入图片描述

  • 通过使用读写锁,可以有效地解决线程竞争共享资源的问题,提高程序的并发性能和稳定性。

3、使用读写锁的示例(QReadWriteLock)

在多线程编程中,使用读写锁需要注意以下几点:

  1. 根据实际情况确定锁的粒度:锁的粒度应该尽可能小,以允许更多的并发访问。如果锁的粒度太大,可能会导致并发性能下降。

  2. 正确获取和释放锁的顺序:当使用多个锁时,需要确保以正确的顺序获取和释放锁,以避免死锁或竞态条件问题。

下面是一个简单的示例,演示如何在C++中使用Qt的读写锁(QReadWriteLock)来保护共享资源的安全访问:

example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

#include <QObject>
#include <QThread>
#include <QReadWriteLock>

class Example : public QObject
{
    
    
    Q_OBJECT

public:
    explicit Example(QObject *parent = nullptr);
    ~Example();

    void start();

private:
    QReadWriteLock m_rwLock;    // 读写锁
    int m_sharedData;			// 共享资源

signals:
    void dataRead(int value);		// 读数据
    void dataWritten(int value);	// 写数据

public slots:
    void readData();             
    void writeData();
};

#endif // EXAMPLE_H

example.cpp

#include "example.h"
#include <QDebug>

Example::Example(QObject *parent) : QObject(parent)
{
    
    
    m_sharedData = 0;   // 初始化变量=0
}

Example::~Example()
{
    
    
}

// 开启线程
void Example::start()
{
    
    
    QThread readerThread;
    QThread writerThread;

    connect(&readerThread, &QThread::started, this, &Example::readData);
    connect(&writerThread, &QThread::started, this, &Example::writeData);

    readerThread.start();
    writerThread.start();
}

void Example::readData()
{
    
    
    while (true) {
    
    
        m_rwLock.lockForRead();
        qDebug() << "Read Data:" << m_sharedData;
        m_rwLock.unlock();
        QThread::msleep(500);
    }
}

void Example::writeData()
{
    
    
    while (true) {
    
    
        m_rwLock.lockForWrite();
        m_sharedData++;
        qDebug() << "Write Data:" << m_sharedData;
        m_rwLock.unlock();
        QThread::msleep(1000);
    }
}

在上述示例中,我们创建了一个共享的整数变量sharedData,并使用QReadWriteLock来保护其访问。
readData函数使用读锁定时读取共享数据,writeData函数使用写锁定时增加共享数据。

通过使用读写锁,我们确保了在读取共享资源时可以并发地访问,而在写入共享资源时只允许一个线程独占访问,从而解决了线程竞争共享资源的问题。

三、总结:

在线程并发编程中,线程竞争共享资源是一个常见的问题,可能导致数据不一致、数据丢失或程序崩溃等严重后果。
使用读写锁是一种有效的解决方案,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。这样可以提高程序的并发性能和稳定性。

希望本篇博客对您有所帮助!

猜你喜欢

转载自blog.csdn.net/ljn1046016768/article/details/131429413
今日推荐