QT线程、互斥量、movetothread

之前做一个实时操作系统时,系统是优先级抢占模式,树莓派4B是多核多线程开发,多个线程设置相同的优先级并安排在不同核上运行,可以实现线程并行;倘若优先级不一致,则优先级高的抢占,优先级低的阻塞,等待高优先级的运行完。

而QT是时间片轮转,在开发时没有注意,当多线程并行了,但其实不是,于是出现了这样的问题:

void RecvSignalThread::run()
{
    while(ThreadCanRun) {

        signal_block_mutex.lock();
        while (needToblock) {
            isblocking = true;
            qDebug() << "signal_block_wait wait" ;
            signal_block_wait.wait(&signal_block_mutex);
            qDebug() << "signal_block_wait wake" ;
            break;
        }
        isblocking = false;
        .............
        .............
        signal_mutex.lock();
        .............
        .............
        signal_mutex.unlock();
        // qDebug() << "run mutex.unlock";
        signal_block_mutex.unlock();
    }
}



void ReplotThread::run()
{
    while(ReplotThreadCanRun) {
        plot_block_mutex.lock();
        while(needToblock) {
            isblocking = true;
            qDebug() << "plot_block_wait wait" ;
            plot_block_wait.wait(&plot_block_mutex);
            qDebug() << "plot_block_wait wake" ;
            break;
        }
        isblocking = false;

        signal_mutex.lock();
        .............
        .............
        signal_mutex.unlock();
        qDebug() << "reploy mutex.unlock";
        plot_block_mutex.unlock();
        QThread::msleep(10);
    }
}

问题:两个线程之间用互斥量通信,但是一个线程疯狂给互斥量上锁,但是另一个线程得过个一会才能抢到上锁机会的。而且我给那个疯狂上锁的线程加几个qdebug就不会了。

线程1保持实时性一直写入数据,线程2以100Hz的频率即10ms更新一次数据(读数据并显示),但是事实上并没有100Hz,有时候过了1s才刷新,间隔的时间不是确定的。难道互斥量被线程1上锁后,线程2不应该阻塞,然后等待线程1释放后,线程2立马再上锁吗,但是看起来线程2没有在互斥量被释放后立即抢到上锁的机会。

即使我把线程2的挂起10ms去掉了,抢到锁的机会也只是提高了一点,但是远没有100Hz。

另外如果我保持线程2的10ms挂起,并且给线程1加几个qdebug,线程2就可以达到100Hz.。

解决办法:

1. 再次学习线程、互斥量相关知识。

        QT线程是时间片轮转。线程2在等信号量的时候,线程1大概率会锁着信号量,因为线程1释放掉信号量之后,又马上上锁了,这是原子性的,很快。所以即使时间片轮到线程2时,也很难出现线程1刚好释放信号量的情况,必须在线程1释放信号量和加锁信号量之间这极短的时间内,刚好时间片转完,轮到线程2才行。

        互斥量的作用是防止出现数据不一致,或许这用不着互斥量。

        以线程+挂起的方式实现一定频率的读取资源并不合适。轮到线程2的时间片时,线程2大概率在加锁的地方一直阻塞,这样时间片就阻塞很长时间,空消耗资源,减少了线程1的运行时间。

        换成主线程中的定时器,不用线程,设置线程优先级,给线程1多点时间

        换成定时器+movetothread,首先,qthread不是线程自身,是线程控制器。QThread是用来控制一个线程的,而不是线程自身。当run()函数结束之后,这个线程就会被终结,但创建的QThread对象仍然存在,且创建的子线程可以循环使用。start()函数可多次调用:QThread只是new出来的一个对象,当调用start()之后,它会新建一个线程,并把run()中的代码放到线程中运行,当运行完成后,线程会结束,但QThread对象还在,所以可再次调用start()函数。

 moveToThread() 是 Qt 中用于将对象移动到另一个线程的方法。通过调用 moveToThread() 函数,可以将一个 QObject 对象从当前线程移动到另一个线程中,从而实现对象在新线程中执行特定的任务。定时器+movetothread的形式或许能够极大的减少占据主线程和线程1的时间,因为其中的对象运行结束应该就不再参与系统调度,直到下一次的触发信号,再跳出来参与系统调度。而线程+挂起的方式会长时间阻塞在加锁的位置,占据很大一块时间没有动作。

尝试再加一个互斥量和一个needtoreplotnew标志位,标志位为volatile BOOL,线程1只读,刷新的线程负责写,这样应该可以在保护大体量数据的同时,也不用对needtoreplotnew标志位加保护,我想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值