Linux Qt使用POSIX多线程条件变量、互斥锁(量)

简介: Linux Qt使用POSIX多线程条件变量、互斥锁(量)今天团建,但是文章也要写。酒要喝好,文要写美,方为我辈程序员的全才之路。嘎嘎 之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子。

Linux Qt使用POSIX多线程条件变量、互斥锁(量)
今天团建,但是文章也要写。酒要喝好,文要写美,方为我辈程序员的全才之路。嘎嘎

之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子。故此来和大家一起分享,希望和大家一起交流。

提到线程,如果在UI编程中,总会和一些耗时操作联系在一起。Qt中处理耗时操作通常有两种方式,一种是将耗时操作放在线程中;另一种则是使用QApplication::processEvents(),防止阻塞UI。从更加通用的角度来讲,我是更倾向于线程的,但对于很多初学者来讲,线程还是有一定难度的。比如说需要对线程间共享的数据提供保护,使用互斥量同步、使用条件变量、使用读写锁同步等;各种同步方式用在什么情况下,开始编程时多线程使用的并不多,无法切身体会到这些问题,后来程序写的多了一点儿,慢慢接触到一些多线程的东西,并且自己也可以学习了相关知识,并用到实际程序中。好了,下面以一个实际的例子为背景,来说明Linux POSIX多线程的一些特性。

程序环境:ubuntu 14.04、 Qt 5.5.1、 Posix多线程(C的用法)

这里简单说下我为什么用Linux C的多线程,因为Qt的多编程对于一些线程的终止时含糊不清楚的,并且一个线程被终止后的资源是无法被清理的,所以我选择是相对底层的一些用法,以后有机会我还会添加线程取消和线程退出的操作。

我自己设定的场景是这样的,在UI主线程中通过界面手动向一个线程间共享的队列中push数据,而另外开启的一个线程则一直在while中pop数据,这算是一个变种的生产者和消费者模式吧。

至于条件变量、互斥量(也就是互斥锁)的初始化在这里不再详细说明,只说明一些相对重要的地方。

  1. UI中向队列push数据(生产者生产数)

这是一个槽函数,当在lineEdit中回车后,则会触发该槽函数,由于该队列是线程间的 共享数据,所以使用了互斥锁进行保护,即该槽操作数据的过程中如果有其他线程想要操作数据,则其他线程则会被阻塞,即访问一个已经被加锁的互斥量的线程会被阻塞。

void Widget::on_le_writeNum_returnPressed()
{

int status;

status = pthread_mutex_lock (&mp_processThread->m_structCondition.mutex);
if (status != 0)
    err_abort (status, "Lock mutex");

QString num = ui->le_writeNum->text();
mp_processThread->queuePushData(num.toInt());

status = pthread_cond_signal (&mp_processThread->m_structCondition.cond);

// status = pthread_cond_broadcast( &mp_processThread->m_structCondition.cond);

if (status != 0)
    err_abort (status, "Signal condition");

status = pthread_mutex_unlock (&mp_processThread->m_structCondition.mutex);
if (status != 0)
    err_abort (status, "Unlock mutex");

}

  

  1. 消费者线程pop数据

该线程使用的是Qt的moveToThread方法创建的线程,这里注意的是,整个类都运行在新的线程中。该槽函数随着线程的启动信号(start())发射后而一直进行while循环。首先对互斥量上锁,之后判断谓词状态,如果队列为空,则等待条件变量。等待条件变量时pthread_cond_wait()会自动释放互斥锁,这样其他线程才能够操作共享数据。从条件变量等待中醒来后,会再次获得互斥锁,以操作共享数据。共享数据被操作完成后,再次释放互斥锁。这是我们使用条件变量等待的一个操作流程,如果我们不使用条件变量等待会是怎样的呢?

void ProcessThread::slot_processData()
{

int status;

while(!mb_stopThread)
{
    status = pthread_mutex_lock (&m_structCondition.mutex);
    if (status != 0)
        err_abort (status, "Lock mutex");

    while(m_queue.empty())   //if queue is empty, wait contion
    {

//使用条件变量等待

        status = pthread_cond_wait(&m_structCondition.cond,
                                   &m_structCondition.mutex);

// qDebug() << "pthread_cond_wait is block func!";

        if (status != 0)
        {
            err_abort (status, "Wait on cond faild");
        }
    }

    while(!m_queue.empty())
    {
        qDebug() << "queue mem is" << m_queue.back();

        m_queue.pop();
    }

    status = pthread_mutex_unlock (&m_structCondition.mutex);
    if (status != 0)
        err_abort (status, "Unlock mutex");

}

}

  

  1. 不使用条件变量等待

①不使用条件变量等待

如果不使用条件变量等待,则消费者线程在很大一部时间内几乎都是在执行 while(1)无限循环,这是很占用CPU资源的,在ubuntu下,使用htop查看的效果 如下:

屏蔽status = pthread_cond_wait(&m_structCondition.cond,

&m_structCondition.mutex);

我们看到,此时CPU是满负荷在运行的,这当然不是一个程序所应有的正常状态。

②使用条件变量的结果

此时我们看到CPU的占用率是很低的,这也是为什么使用条件变量的原因之一,让不满足的条件的线程挂起,而不是在浪费CPU资源。条件变量是 允许使用队列的线程之间交换队列状态信息的机制。那么当我们还没有掌握线程条件变量的用法时,又遇到这种情况时,该怎么做呢?简单,加个5ms的延时即可,5ms对我们来讲时间极短极短,但对计算机来讲,已经挺长时间了。

最后,当我们关掉UI窗口时,会有这样一句消息:

QThread: Destroyed while thread is still running

线程正在运行时就被破坏了,这个我们接下来会说,那就是如何退出线程、终止线程以及取消线程等操作了。

欢迎大家一起交流!
原文地址https://www.cnblogs.com/d-h-/p/11286171.html

相关文章
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
网络协议 安全
QT多线程
本文详细介绍了在Qt中如何正确使用QThread以及信号槽跨线程的使用方式,包括线程的正确退出方法和QObject在不同线程中创建子对象时可能遇到的问题。同时,文章还提供了相关博客和资料的链接,用于进一步学习和参考。
600 3
|
数据库 数据库管理
qt对sqlite数据库多线程的操作
本文总结了在Qt中进行SQLite数据库多线程操作时应注意的四个关键问题,包括数据库驱动加载、加锁、数据库的打开与关闭,以及QsqlQuery变量的使用。
1367 1
|
调度
【浅入浅出】Qt多线程机制解析:提升程序响应性与并发处理能力
在学习QT线程的时候我们首先要知道的是QT的主线程,也叫GUI线程,意如其名,也就是我们程序的最主要的一个线程,主要负责初始化界面并监听事件循环,并根据事件处理做出界面上的反馈。但是当我们只限于在一个主线程上书写逻辑时碰到了需要一直等待的事件该怎么办?它的加载必定会带着主界面的卡顿,这时候我们就要去使用多线程。
769 6
自己动手写QT多线程demo
本文是作者关于如何编写Qt多线程demo的教程,介绍了如何实现多线程功能,包括可暂停和继续的功能。文章提供了部分示例代码,展示了如何创建线程类、启动和管理线程,以及线程间的通信。同时,还提供了相关参考资料和免费下载链接。
507 0
|
安全 算法 Linux
【Linux】线程安全——补充|互斥、锁|同步、条件变量(下)
【Linux】线程安全——补充|互斥、锁|同步、条件变量(下)
246 0
|
存储 安全 Linux
【Linux】线程安全——补充|互斥、锁|同步、条件变量(上)
【Linux】线程安全——补充|互斥、锁|同步、条件变量(上)
293 0
|
缓存 Linux 编译器
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
466 0
|
存储 Linux 调度
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
389 0
|
Linux
Linux IPC实践(10) --Posix共享内存
1. 创建/获取一个共享内存 #include #include /* For mode constants */ #include /* For O...
1241 0

热门文章

最新文章