线程同步之:QSemaphore

1、QSemaphore(信号量):针对“资源 >1个”的情况。

1.1

QMutex:只保护一个资源。

信号量:通常用于保护“一定数量”的相同资源。

前面的几种锁都是用来保护“只有一个变量”的互斥量的。可是还有些互斥量(资源)的数量并不止一个,好比一个电脑安装了2个打印机,我已经申请了一个,可是我不能霸占这两个,你来访问的时候若是发现还有空闲仍然能够申请到的。

因而这个互斥量能够分为2部分已使用未使用。一个线程在申请的时候,会对未使用到的部分进行加锁操做,若是加锁失败则阻塞。若是加锁成功,即又有一个资源被使用了,因而则将已使用到的部分解锁一个。

1.2

比如信号量的一个典型应用:同步生产者和消费者之间对循环缓冲区的访问;

以著名的生产者消费者问题为例,分析问题:生产者须要的是空闲位置存放产品,结果是可取的产品多了一个。因而,咱们能够定义2信号量:QSemaphore  freeSpace(给生产者使用)和 QSemaphore  usedSpace(给消费者使用)。

1.3

1.4 相关成员函数

1.5 示例

const int BufferSize = 8;
//这2个buf,就是要进行保护管理的资源
int buffer1[BufferSize];//
int buffer2[BufferSize];//
int curBuf=1; //当前正在写入的Buffer

int bufNo=0; //采集的缓冲区序号

quint8   counter=0;//数据生成器

QSemaphore emptyBufs(2);//信号量:空的缓冲区个数,初始资源个数为2
QSemaphore fullBufs; //满的缓冲区个数,初始资源为0
//采用双缓冲方式:进行模拟数据采集。buffer1、buffer2
void QThreadDAQ::run() //生产者
{
    m_stop=false;//启动线程时令m_stop=false
    bufNo=0;//缓冲区序号
    curBuf=1; //当前写入使用的缓冲区
    counter=0;//数据生成器

    int n=emptyBufs.available();
    if (n<2)  //保证 线程启动时emptyBufs.available==2
      emptyBufs.release(2-n);

    while(!m_stop)//循环主体
    {
		//============步骤2:=============//
		//1.使用信号量emptyBufs获取一个资源:即获取一个空的缓冲区。emptyBufs--; 少一个
        emptyBufs.acquire();
		
		//2.每隔50ms,使counter值加1,然后写入当前正在写入的缓冲区。
		//写入哪个缓冲区由curBuf决定。
		//counter:是模拟采集的数据。连续增加:可以判断采集的数据是否连续
        for(int i=0;i< BufferSize;i++) //产生一个缓冲区的数据
        {
            if (curBuf==1)
                buffer1[i]=counter; //向缓冲区写入数据
            else
                buffer2[i]=counter;
            counter++; //模拟数据采集卡产生数据

            msleep(50); //每50ms产生一个数
        }

		//3.完成for循环后,正好写满一个缓冲区buffer。这时改变curBuf的值,切换用于写入的缓冲区
        bufNo++;//缓冲区序号
        if (curBuf==1) // 切换当前写入缓冲区
          curBuf=2;
        else
          curBuf=1;
		
		//============步骤3:=============//
		//4.写满一个缓冲区后,使用信号量fullBufs释放一个资源。这时fullsBufs.available==1,表示有一个缓冲区被写满了
		//这样,QThreadShow线程里使用fullBufs.acquire()就可以获得一个资源,可以读取已写满的缓冲区里的数据。
        fullBufs.release(); //有了一个满的缓冲区,available==1
    }
    quit();//退出线程
}
void QThreadShow::run()	//消费者线程
{
    m_stop=false;//启动线程时令m_stop=false

    int n=fullBufs.available();//可用资源
    if (n>0)
       fullBufs.acquire(n); //将fullBufs可用资源个数初始化为0(获取n个资源后,就剩0个了!相当于初始化为0个)

    while(!m_stop)//循环主体
    {
		//============步骤1:=============//
		//1.监测是否有已经写满数据的缓冲区
		//以阻塞方式获取一个资源。只有当QThreadDAQ线程里写满一个缓冲区,执行一次fullBufs.release()后,
		//fullBufs.acquire()才能获得资源并执行后面的代码。
        fullBufs.acquire(); //fullBufs.available==0阻塞,等待有缓冲区满。

		//============步骤4:=============//
        int bufferData[BufferSize];
        int seq=bufNo;
		//2.立刻读取数据:用临时变量bufferData[BufferSize]将缓冲区里的数据读取出来
        if(curBuf==1) //当前在写入的缓冲区是1,那么满的缓冲区是2
            for (int i=0;i<BufferSize;i++)
               bufferData[i]=buffer2[i]; //快速拷贝缓冲区数据
        else
            for (int i=0;i<BufferSize;i++)
               bufferData[i]=buffer1[i];
		
		//3.释放缓冲区,给QThreadDAQ线程用于写入
		//释放一个空缓冲区。相当于emptyBufs++;多一个空缓冲区资源
        emptyBufs.release();//给信号量emptyBufs释放一个资源

		//4.发射信号newValue,给主线程dialog读取数据并显示
        emit    newValue(bufferData,BufferSize,seq);//给主线程传递数据
    }
    quit();
}

1.5.1 先启动“消费者线程”、2个线程全部使用terminate强制关闭

1.5.2

1.5.3

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: PyQt5中的QThread类可以用于创建多线程应用程序。在多线程应用程序中,同步是非常重要的,因为多个线程可能会同时访问同一个资源。为了确保线程安全,可以使用互斥锁或信号量等同步机制来保护共享资源。在PyQt5中,可以使用QMutex和QSemaphore类来实现同步。QMutex类提供了一个互斥锁,可以确保同一时间只有一个线程可以访问共享资源。QSemaphore类提供了一个信号量,可以控制同时访问共享资源的线程数量。在使用QThread类创建多线程应用程序时,需要注意同步问题,以确保应用程序的正确性和稳定性。 ### 回答2: PyQt5在多线程方面提供了很好的支持,通过QThread类,我们可以创建多个线程,从而实现并发操作。QThread是Qt的线程类,它封装了线程的所有操作,如启动、停止、暂停、恢复等。下面我们来探讨一下如何在PyQt5中实现多线程同步。 1.线程间通信 由于多个线程是并发执行的,如果在某个线程中修改了共享变量,可能会对其他线程产生影响,因此为了保证程序的正确性,在多线程编程中必须保证线程间同步,确保线程之间通信的正确性、完整性和准确性。为了实现线程间通信,在PyQt5中提供了多种方法: a.使用信号和槽方法:信号和槽方法是Qt中的一种消息传递机制,由于多个线程之间不能访问同一个变量,只能通过信号和槽方法来交换信息。 b.使用共享变量:通过将变量声明为共享变量,多个线程可以访问这个变量,通过加锁和解锁保证同步。 c.使用队列:在一个线程中,将共享变量或计算结果放入队列中,然后在另一个线程中取出这些结果。 2.加锁和解锁 为了保证多线程的同步,PyQt5提供了多种锁的类型,如互斥锁、读写锁、信号量、条件变量等。互斥锁是最简单的一种锁,通常用于多个线程之间对同一共享资源的互斥访问。在一个线程中执行临界区代码时,需要加锁,以避免其他线程同时访问这个共享资源。在PyQt5中,可以使用QMutex类或QReadWriteLock类实现互斥锁。 3.线程池 线程池是一种常见的多线程应用模型,它由一个线程池管理器、工作线程和任务队列组成。线程池管理器负责创建、销毁和管理工作线程,工作线程执行实际的任务,任务队列用于存储等待执行的任务。线程池的优点是可以在一定程度上控制线程的数量,防止因线程过多导致程序崩溃,提高了程序的性能。 总之,在PyQt5中实现多线程同步需要注意线程间通信、加锁和解锁以及使用线程池等方法来提高程序的效率和可靠性。除此之外,还需要注意程序的实际应用场景和数据结构的合理设计,以达到更好的多线程同步效果。 ### 回答3: 在PyQt5中,QThread用于在单独的线程中执行耗时或长时间运行的任务。它是基于QObject的子类,可以通过信号和槽与其他线程和主线程进行通信。但是,在使用QThread时,需要注意多线程同步的问题,以避免出现不稳定和不可预测的行为。 为了避免多线程同步问题,可以采用以下几种方法: 1. 使用锁(QMutex)或信号量(QSemaphore): 使用锁或信号量可以确保多个线程不会同时访问共享资源。在一个线程中,可以使用QMutex.lock()函数来获得锁,使用QMutex.unlock()函数来释放锁。当一个线程正在使用共享资源时,其他线程将被阻塞,直到锁被释放为止。同样地,可以使用QSemaphore.acquire()和QSemaphore.release()函数实现信号量。 2. 使用互斥量(QReadWriteLock): 互斥量是一种特殊的锁,用于控制多个线程对同一资源的访问。QReadWriteLock类提供了读写锁,其中读锁可被多个线程同时保持,但写锁只能由一个线程保持,并且在此期间其他线程将被阻塞。 3. 使用信号和槽: 在使用QThread时,可以通过信号和槽来实现多线程同步。可以在主线程中定义一个信号,并将其连接到QThread中的槽。当QThread中的任务完成时,可以通过信号来通知主线程更新UI。 总之,多线程同步是编写可靠和高质量的多线程代码的关键部分。需要根据应用程序的要求选择合适的同步机制,并在代码中正确地实现它们。通过正确使用多线程同步机制,可以确保应用程序的可靠性和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值