QThread库是QT中提供的跨平台多线程实现方案,使用时需要继承QThread这个基类,并重写实现内部的Run方法,由于该库是基本库,默认依赖于QtCore.dll这个基础模块,在使用时无需引入其他模块.

实现简单多线程: QThread库提供了跨平台的多线程管理方案,通常一个QThread对象管理一个线程,在使用是需要从QThread类继承并重写内部的Run方法,并在Run方法内部实现多线程代码.

#include <QCoreApplication>
#include <iostream>
#include <QThread> class MyThread: public QThread
{ protected:
volatile bool m_to_stop; protected:
// 线程函数必须使用Run作为开始
void run()
{
for(int x=0; !m_to_stop && (x <10); x++)
{
msleep(1000);
std::cout << objectName().toStdString() << std::endl;
}
} public:
MyThread()
{
m_to_stop = false;
} // 用于设置结束符号为真
void stop()
{
m_to_stop = true;
} // 输出线程运行状态
void is_run()
{
std::cout << "Thread Running = " << isRunning() << std::endl;
} // 输出线程完成状态(是否结束)
void is_finish()
{
std::cout << "Thread Finished = " << isFinished() << std::endl;
} }; int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); // 定义线程数组
MyThread thread[10]; // 设置线程对象名字
for(int x=0;x<10;x++)
{
thread[x].setObjectName(QString("thread => %1").arg(x));
} // 批量调用run执行
for(int x=0;x<10;x++)
{
thread[x].start();
thread[x].is_run();
thread[x].isFinished();
} // 批量调用stop关闭
for(int x=0;x<10;x++)
{
thread[x].wait();
thread[x].stop(); thread[x].is_run();
thread[x].is_finish();
} return a.exec();
}

向线程中传递参数: 线程在执行前可以通过调用MyThread中的自定义函数,并在函数内实现参数赋值,实现线程传参操作.

#include <QCoreApplication>
#include <iostream>
#include <QThread> class MyThread: public QThread
{
protected:
int m_begin;
int m_end;
int m_result; void run()
{
m_result = m_begin + m_end;
} public:
MyThread()
{
m_begin = 0;
m_end = 0;
m_result = 0;
} // 设置参数给当前线程
void set_value(int x,int y)
{
m_begin = x;
m_end = y;
} // 获取当前线程名
void get_object_name()
{
std::cout << "this thread name => " << objectName().toStdString() << std::endl;
} // 获取线程返回结果
int result()
{
return m_result;
}
}; int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); MyThread thread[3]; // 分别将不同的参数传入到线程函数内
for(int x=0; x<3; x++)
{
thread[x].set_value(1,2);
thread[x].setObjectName(QString("thread -> %1").arg(x));
thread[x].start();
} // 等待所有线程执行结束
for(int x=0; x<3; x++)
{
thread[x].get_object_name();
thread[x].wait();
} // 获取线程返回值并相加
int result = thread[0].result() + thread[1].result() + thread[2].result();
std::cout << "sum => " << result << std::endl; return a.exec();
}

QMutex 互斥同步线程锁: QMutex类是基于互斥量的线程同步锁,该锁lock()锁定与unlock()解锁必须配对使用,线程锁保证线程间的互斥,利用线程锁能够保证临界资源的安全性.

  • 线程锁解决的问题: 多个线程同时操作同一个全局变量,为了防止资源的无序覆盖现象,从而需要增加锁,来实现多线程抢占资源时可以有序执行.
  • 临界资源(Critical Resource): 每次只允许一个线程进行访问 (读/写)的资源.
  • 线程间的互斥(竞争): 多个线程在同一时刻都需要访问临界资源.
  • 一般性原则: 每一个临界资源都需要一个线程锁进行保护.
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QMutex> static QMutex g_mutex; // 线程锁
static QString g_store; // 定义全局变量 class Producer : public QThread
{
protected:
void run()
{
int count = 0; while(true)
{
// 加锁
g_mutex.lock(); g_store.append(QString::number((count++) % 10));
std::cout << "Producer -> "<< g_store.toStdString() << std::endl; // 释放锁
g_mutex.unlock();
msleep(900);
}
}
}; class Customer : public QThread
{
protected:
void run()
{
while( true )
{
g_mutex.lock();
if( g_store != "" )
{
g_store.remove(0, 1);
std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl;
} g_mutex.unlock();
msleep(1000);
}
}
}; int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); Producer p;
Customer c; p.setObjectName("producer");
c.setObjectName("curstomer"); p.start();
c.start(); return a.exec();
}

QMutexLocker是在QMutex基础上简化版的线程锁,QMutexLocker会保护加锁区域,并自动实现互斥量的锁定和解锁操作,可以将其理解为是智能版的QMutex锁,该锁只需要在上方代码中稍加修改即可.

#include <QMutex>
#include <QMutexLocker> static QMutex g_mutex; // 线程锁
static QString g_store; // 定义全局变量 class Producer : public QThread
{
protected:
void run()
{
int count = 0; while(true)
{
// 增加智能线程锁
QMutexLocker Locker(&g_mutex); g_store.append(QString::number((count++) % 10));
std::cout << "Producer -> "<< g_store.toStdString() << std::endl; msleep(900);
}
}
};

互斥锁存在一个问题,每次只能有一个线程获得互斥量的权限,如果在程序中有多个线程来同时读取某个变量,那么使用互斥量必须排队,效率上会大打折扣,基于QReadWriteLock读写模式进行代码段锁定,即可解决互斥锁存在的问题.

QReadWriteLock 读写同步线程锁: 该锁允许用户以同步读lockForRead()或同步写lockForWrite()两种方式实现保护资源,但只要有一个线程在以写的方式操作资源,其他线程也会等待写入操作结束后才可继续读资源.

#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QMutex>
#include <QReadWriteLock> static QReadWriteLock g_mutex; // 线程锁
static QString g_store; // 定义全局变量 class Producer : public QThread
{
protected:
void run()
{
int count = 0; while(true)
{
// 以写入方式锁定资源
g_mutex.lockForWrite(); g_store.append(QString::number((count++) % 10)); // 写入后解锁资源
g_mutex.unlock(); msleep(900);
}
}
}; class Customer : public QThread
{
protected:
void run()
{
while( true )
{
// 以读取方式写入资源
g_mutex.lockForRead();
if( g_store != "" )
{
std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl;
} // 读取到后解锁资源
g_mutex.unlock();
msleep(1000);
}
}
}; int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); Producer p1,p2;
Customer c1,c2; p1.setObjectName("producer 1");
p2.setObjectName("producer 2"); c1.setObjectName("curstomer 1");
c2.setObjectName("curstomer 2"); p1.start();
p2.start(); c1.start();
c2.start(); return a.exec();
}

QSemaphore 基于信号线程锁: 信号量是特殊的线程锁,信号量允许N个线程同时访问临界资源,通过acquire()获取到指定资源,release()释放指定资源.

#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QSemaphore> const int SIZE = 5;
unsigned char g_buff[SIZE] = {0}; QSemaphore g_sem_free(SIZE); // 5个可生产资源
QSemaphore g_sem_used(0); // 0个可消费资源 // 生产者生产产品
class Producer : public QThread
{
protected:
void run()
{
while( true )
{
int value = qrand() % 256; // 若无法获得可生产资源,阻塞在这里
g_sem_free.acquire(); for(int i=0; i<SIZE; i++)
{
if( !g_buff[i] )
{
g_buff[i] = value;
std::cout << objectName().toStdString() << " --> " << value << std::endl;
break;
}
} // 可消费资源数+1
g_sem_used.release(); sleep(2);
}
}
}; // 消费者消费产品
class Customer : public QThread
{
protected:
void run()
{
while( true )
{
// 若无法获得可消费资源,阻塞在这里
g_sem_used.acquire(); for(int i=0; i<SIZE; i++)
{
if( g_buff[i] )
{
int value = g_buff[i]; g_buff[i] = 0;
std::cout << objectName().toStdString() << " --> " << value << std::endl;
break;
}
} // 可生产资源数+1
g_sem_free.release(); sleep(1);
}
}
}; int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); Producer p1;
Customer c1; p1.setObjectName("producer");
c1.setObjectName("curstomer"); p1.start();
c1.start(); return a.exec();
}

C/C++ Qt QThread 线程组件应用的更多相关文章

  1. Qt QThread 线程创建,线程同步,线程通信 实例

    1.  继承QThread, 实现run()方法, 即可创建线程. 2. 实例1 代码 myThread.h #ifndef MYTHREAD_H #define MYTHREAD_H #includ ...

  2. Qt经典—线程、事件与Qobject(耳目一新)

    介绍 You’re doing it wrong. — Bradley T. Hughes 线程是qt channel里最流行的讨论话题之一.许多人加入了讨论并询问如何解决他们在运行跨线程编程时所遇到 ...

  3. Qt经典—线程、事件与Qobject

    介绍 You’re doing it wrong. — Bradley T. Hughes 线程是qt channel里最流行的讨论话题之一.许多人加入了讨论并询问如何解决他们在运行跨线程编程时所遇到 ...

  4. Qt同步线程(比较清楚,而且QMutex QMutexLocker QReadWriteLock QSemaphore QWaitCondition 每个都有例子)

    Qt同步线程 我们知道,多线程有的时候是很有用的,但是在访问一些公共的资源或者数据时,需要进行同步,否则会使数据遭到破坏或者获取的值不正确.Qt提供了一些类来实现线程的同步,如QMutex,QMute ...

  5. [转]QT子线程与主线程的信号槽通信-亲测可用!

    近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI.所以,网络通信端采用新开线程的方式.在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦.网上提供了很多同一线程不同类间采用信号槽 ...

  6. 界面编程之QT的线程20180731

    /*******************************************************************************************/ 一.为什么需 ...

  7. 重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)

    背景描述: 以前,继承 QThread 重新实现 run() 函数是使用 QThread唯一推荐的使用方法.这是相当直观和易于使用的.但是在工作线程中使用槽机制和Qt事件循环时,一些用户使用错了.Qt ...

  8. Qt 子线程更新Ui

    最近做练习,写一个Qt版的飞机大战,需要用子线程更新UI,发现Qt子线程不能更新Ui,否则程序会崩溃.在网上百度了下,说是需要在子线程自定义信号,然后在线程回调的run()函数里发射信号,主线程连接信 ...

  9. Qt同步线程(QMutex QMutexLocker QReadWriteLock QSemaphore QWaitCondition )

    Qt同步线程 我们知道,多线程有的时候是很有用的,但是在访问一些公共的资源或者数据时,需要进行同步,否则会使数据遭到破坏或者获取的值不正确.Qt提供了一些类来实现线程的同步,如QMutex,QMute ...

  10. QThread 线程暂停 停止功能的实现

    为了实现Qt中线程的暂停运行,和停止运行的控制功能 需要在设置两个static型控制变量. //终止原始数据单元进队出队,并清空数据. static bool stopSign; //原始数据单元队列 ...

随机推荐

  1. GIL 锁或将在 CPython 中成为可选项

    哈喽大家好,我是咸鱼 几天前有媒体报道称,经过多次辩论,Python 指导委员会打算批准通过 PEP 703 提案,让 GIL(全局解释器)锁在 CPython 中成为一个可选项 PEP 703 提案 ...

  2. django的简单学习

    前言 以下项目实现基于一个投票系统 安装django 命令行安装 pip install django pycharm安装 pycharm的setting里找到这个,点击+号,搜索django 点击I ...

  3. 三、redis集群搭建

    系列导航 一.redis单例安装(linux) 二.redis主从环境搭建 三.redis集群搭建 四.redis增加密码验证 五.java操作redis 环境:centos7需要的安装包: redi ...

  4. Blazor的技术优点

    Blazor是一种使用.NET和C#构建客户端Web应用程序的新兴技术.它允许开发者在浏览器中直接运行.NET代码,而无需依赖JavaScript.Blazor的技术优点主要表现在以下几个方面: 单一 ...

  5. 【面试题精讲】为什么G1收集器不需要调优性能也很优秀

    G1(Garbage-First)收集器是一种面向服务器端应用的垃圾回收器,它在JDK 7u4版本中首次引入,主要用于替代CMS(Concurrent Mark Sweep)收集器.相比于其他垃圾回收 ...

  6. [转帖]SQL Server 中如何移动tempdb到新的位置

    https://www.cnblogs.com/OpenCoder/p/10322904.html 操作步骤:1.检查tempdb的逻辑名字和它的存在位置.可以使用下面语句: SELECT name, ...

  7. [转帖]django使用html渲染页面样式+数据库管理员的创建

    一.django页面渲染 1.在templates中创建html格式的文件-index.html,在该文件中添加body,设置样式,比如: <h1 style = "backgroun ...

  8. [转帖]Region Merge Config

    TiKV replicates a segment of data in Regions via the Raft state machine. As data writes increase, a ...

  9. [转帖]k8s对接ceph,ceph-csi方式

    1.上传ceph-csi-yaml和ceph-csi-image 两个文件夹到服务器 2.加载 ceph-csi-image里面的镜像 3.将加载好的镜像上传到本地harbor上. 4.修改ceph- ...

  10. [转帖]Linux命令拾遗-动态追踪工具

      原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介# 这是Linux命令拾遗系列的第六篇,本篇主要介绍工作中常用的动态追踪工具strace.arthas.bpft ...