C++代码中去除和Qt相关的代码

C++代码中去除和Qt相关的代码,第1张

这个还真不好改,你即便是修改了ReceiveThread类定义部分代码,那调用该类的对象的所有调用代码也要修改,因为有些方法是属于继承于QThread类才有的。有时候修改代码就是有些麻烦,所以软件的设计才那么重要啊。

qthread wait后面的语句还执行。

这个waitForFinished(2000)是让程序程等待process完成。

1、明确打开文件的位置和名称,注册表编辑器名称为regedit

2、建立一个类MyThread,用于继承QThread类,并声明虚函数run(),该函数用于程序调用该进程时自动调用。

#include <QThread>

class MyThread : public QThread

{

public

void run();

};

需要设置"控制管脚状态"。qthread中收不到readyread信号需要设置"控制管脚状态"。一个QThread代表了一个在应用程序中可以独立控制的线程,它与进程中的其他线程分享数据,但是是独立执行的。

Qt作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功能。为了满足用户构造复杂图形界面系统的需求,Qt提供了丰富的多线程编程支持。从 22 版本开始,Qt主要从下面三个方面对多线程编程提供支持:一、构造了一些基本的与平台无关的线程类;二、提交用户自定义事件的 Thread-safe方式;三、多种线程间同步机制,如信号量,全局锁。这些都给用户提供了极大的方便。不过,在某些情况下,使用定时器机制能够比利用 Qt本身的多线程机制更方便地实现所需要的功能,同时也避免了不安全的现象发生。本文不仅对 Qt中的多线程支持机制进行了讨论,还着重探讨了利用定时器机制模拟多线程编程的方法。

1、系统对多线程编程的支持

不同的平台对 Qt 的多线程支持方式是不同的。当用户在 Windows *** 作系统上安装 Qt 系统时,线程支持是编译器的一个选项,在 Qt 的 mkfiles 子目录中包括了不同种类编译器的编译文件,其中带有 -mt 后缀的文件才是支持多线程的。

而在 Unix *** 作系统中,线程的支持是通过在运行 configure 脚本文件时添加 -thread选项加入的。安装过程将创建一个独立的库,即libqt-mt,因此要支持多线程编程时,必须与该库链接(链接选项为-lqt-mt),而不是与通常的 Qt 库(-lqt)链接。

另外,无论是何种平台,在增加线程支持时都需要定义宏QT_THREAD_SUPPORT(即增加编译选项-DQT_THREAD_SUPPORT)。在 Windows *** 作系统中,这一点通常是在qconfigh 文件中增加一个选项来实现的。而在 Unix 系统中通常添加在有关的 Makefile 文件中。

2、Qt中的线程类

在Qt 系统中与线程相关的最重要的类当然是 QThread 类,该类提供了创建一个新线程以及控制线程运行的各种方法。线程是通过QThread::run() 重载函数开始执行的,这一点很象 Java 语言中的线程类。在 Qt 系统中,始终运行着一个GUI主事件线程,这个主线程从窗口系统中获取事件,并将它们分发到各个组件去处理。在 QThread类中还有一种从非主事件线程中将事件提交给一个对象的方法,也就是 QThread::postEvent()方法,该方法提供了 Qt 中的一种Thread-safe 的事件提交过程。提交的事件被放进一个队列中,然后 GUI主事件线程被唤醒并将此事件发给相应的对象,这个过程与一般的窗口系统事件处理过程是一样的。值得注意的是,当事件处理过程被调用时,是在主事件线程中被调用的,而不是在调用QThread::postEvent 方法的线程中被调用。比如用户可以从一个线程中迫使另一个线程重画指定区域:

QWidget mywidget;

QThread::postEvent(mywidget, new QPaintEvent(QRect(0,0,100,100)));

然而,只有一个线程类是不够的,为编写出支持多线程的程序,还需要实现两个不同的线程对共有数据的互斥访问,因此 Qt 还提供了 QMutex类,一个线程在访问临界数据时,需要加锁,此时其他线程是无法对该临界数据同时加锁的,直到前一个线程释放该临界数据。通过这种方式才能实现对临界数据的原子 *** 作。

除此之外,还需要一些机制使得处于等待状态的线程在特定情况下被唤醒。QWaitCondition 类就提供了这种功能。当发生特定事件时,QWaitCondition 将唤醒等待该事件的所有线程或者唤醒任意一个被选中的线程。

3、用户自定义事件在多线程编程中的应用

在 Qt 系统中,定义了很多种类的事件,如定时器事件、鼠标移动事件、键盘事件、窗口控件事件等。通常,事件都来自底层的窗口系统,Qt 的主事件循环函数从系统的事件队列中获取这些事件,并将它们转换为 QEvent,然后传给相应的 QObjects 对象。

除此之外,为了满足用户的需求,Qt 系统还提供了一个 QCustomEvent 类,用于用户自定义事件,这些自定义事件可以利用QThread::postEvent() 或者QApplication::postEvent() 被发给各种控件或其他 QObject实例,而 QWidget 类的子类可以通过 QWidget::customEvent()事件处理函数方便地接收到这些自定义的事件。需要注意的是:QCustomEvent 对象在创建时都带有一个类型标识 id以定义事件类型,为了避免与 Qt 系统定义的事件类型冲突,该 id 值应该大于枚举类型 QEvent::Type 中给出的 "User" 值。

在下面的例子中,显示了多线程编程中如何利用用户自定义事件类。

UserEvent类是用户自定义的事件类,其事件标识为3467Array8,显然不会与系统定义的事件类型冲突。

class UserEvent : public QCustomEvent //用户自定义的事件类

{

public:

UserEvent(QString s) : QCustomEvent(3467Array8), sz(s) { ; }

QString str() const { return sz; }

private:

QString sz;

};

UserThread类是由QThread类继承而来的子类,在该类中除了定义有关的变量和线程控制函数外,最主要的是定义线程的启动函数UserThread::run(),在该函数中创建了一个用户自定义事件UserEvent,并利用QThread类的postEvent函数提交该事件给相应的接收对象。

class UserThread : public QThread //用户定义的线程类

{

public:

UserThread(QObject r, QMutex m, QWaitCondition c);

QObject receiver;

}

void UserThread::run() //线程类启动函数,在该函数中创建了一个用户自定义事件

{UserEvent re = new UserEvent(resultstring);

QThread::postEvent(receiver, re);

}

UserWidget类是用户定义的用于接收自定义事件的QWidget类的子类,该类利用slotGo()函数创建了一个新的线程recv(UserThread类),当收到相应的自定义事件(即id为3467Array8)时,利用customEvent函数对事件进行处理。

void UserWidget::slotGo() //用户定义控件的成员函数

{ mutexlock();

if (! recv)

recv = new UserThread(this, &mutex, &condition);

recv->start();

mutexunlock();

}

void UserWidget::customEvent(QCustomEvent e) //用户自定义事件处理函数

{ if (e->type()==3467Array8)

{

UserEvent re = (UserEvent ) e;

newstring = re->str();

}

}

在这个例子中,UserWidget对象中创建了新的线程UserThread,用户可以利用这个线程实现一些周期性的处理(如接收底层发来的消息等),一旦满足特定条件就提交一个用户自定义的事件,当UserWidget对象收到该事件时,可以按需求做出相应的处理,而一般情况下,UserWidget对象可以正常地执行某些例行处理,而完全不受底层消息的影响。

4、利用定时器机制实现多线程编程

为了避免Qt系统中多线程编程带来的问题,还可以使用系统中提供的定时器机制来实现类似的功能。定时器机制将并发的事件串行化,简化了对并发事件的处理,从而避免了thread-safe方面问题的出现。

在下面的例子中,同时有若干个对象需要接收底层发来的消息(可以通过Socket、FIFO等进程间通信机制),而消息是随机收到的,需要有一个GUI主线程专门负责接收消息。当收到消息时主线程初始化相应对象使之开始处理,同时返回,这样主线程就可以始终更新界面显示并接收外界发来的消息,达到同时对多个对象的控制;另一方面,各个对象在处理完消息后需要通知GUI主线程。对于这个问题,可以利用第3节中的用户自定义事件的方法,在主线程中安装一个事件过滤器,来捕捉从各个对象中发来的自定义事件,然后发出信号调用主线程中的一个槽函数。

另外,也可以利用Qt中的定时器机制实现类似的功能,而又不必担心Thread-safe问题。下面就是有关的代码部分:

在用户定义的Server类中创建和启动了定时器,并利用connect函数将定时器超时与读取设备文件数据相关联:

Server:: Server(QWidget parent) : QWidget(parent)

{

readTimer = new QTimer(this); //创建并启动定时器

connect(readTimer, SIGNAL(timeout()), this, SLOT(slotReadFile())); //每当定时器超时时调用函数slotReadFile读取文件

readTimer->start(100);

}

slotReadFile函数负责在定时器超时时,从文件中读取数据,然后重新启动定时器:

int Server::slotReadFile() // 消息读取和处理函数

{

readTimer->stop(); //暂时停止定时器计时

ret = read(file, buf ); //读取文件

if(ret == NULL)

{ readTimer->start(100); //当没有新消息时,重新启动定时器

return(-1);

}

else

根据buf中的内容将消息分发给各个相应的对象处理……;

readTimer->start(100); //重新启动定时器

}

在该程序中,利用了类似轮循的方式定时对用户指定的设备文件进行读取,根据读到的数据内容将信息发送到各个相应的对象。用户可以在自己的GUI主线程中创建一个Server类,帮助实现底层的消息接收过程,而本身仍然可以处理诸如界面显示的问题。当各个对象完成处理后,通过重新启动定时器继续进行周期性读取底层设备文件的过程。当然,这种方法适合于各对象对事件的处理时间较短,而底层设备发来消息的频率又相对较慢的情况。在这种情况下,上述方法完全可以满足用户的需求,而又避免了处理一些与线程并发有关的复杂问题。

当然,利用定时器机制实现多线程编程在某些方面具有一定的局限性,有关到底如何实现多线程编程,如何编写出效率更高的代码,还有待于开发者进一步研究和探讨。

在Unix系统中,时间片算法是线程排好队,按照时间片逐个执行,在单位时间片内跑不完,就等下一轮!所以不存在分不到时间片的情况!

2、一个线程启动以后,只要不是在锁池,等待池,那它就是runnable状态!!!至于能不能分到时间片(如:windows系统抢占式),并不会影响它的状态!

可以新开一个Python线程,主线程与线程之间通过queue通信。

PyQt本身可以使用Qt线程(QThread),统一进程的不同QThread之间可以是使用signal/slot机制的!

基本思想:建立了一个队列,为每一个Thread保存了一个对象锁,保证按顺序执行。线程启动的时候,使随机的,但是执行代码是按顺序的。

import javautilLinkedList;

import javautilQueue;

public class ThreadTest {

private static Queue qThread=new LinkedList();//线程同步对象队列

public static synchronized void putObject(Object t){

qThreadoffer(t);

}

public static synchronized Object getObject(){

return qThreadpoll();

}

public static void waitThread(Object t) throws InterruptedException{

synchronized(t){

twait();

}

}

public static void notifyThread(){

Object obj=ThreadTestgetObject();

if(obj==null)

return;

synchronized(obj){

objnotify();

}

}

public static void main(String[] args) throws InterruptedException {

int i = 0;

boolean isFirst=true;

while (i < 10) {

Object obj=new Object();

if(i>0){

isFirst=false;

ThreadTestputObject(obj);

}

Thread t2 = new Thread2(isFirst,obj);

Object obj2=new Object();

ThreadTestputObject(obj2);

Thread t3 = new Thread3(obj2);

t2start();

t3start();

i++;

}

}

}

/

线程2

@author HarryWANG

/

class Thread2 extends Thread {

private boolean isFirst=false;

private Object obj;

public Thread2(boolean f,Object obj){

thisisFirst=f;

thisobj=obj;

}

@Override

public void run() {

if(!thisisFirst){

Systemoutprintln(thisgetName()+"等待");

try{

ThreadTestwaitThread(obj);

}catch(InterruptedException e){

eprintStackTrace();

}

}

Systemoutprintln("启动"+thisgetName()+"");

try {

sleep(3000);//等待3秒,为了测试

} catch (InterruptedException e) {

eprintStackTrace();

}

Systemoutprintln("停止"+thisgetName()+"");

ThreadTestnotifyThread();

}

}

class Thread3 extends Thread {

private Object obj;

public Thread3(Object obj){

thisobj=obj;

}

@Override

public void run() {

Systemoutprintln(thisgetName()+"等待");

try{

ThreadTestwaitThread(obj);

}catch(InterruptedException e){

eprintStackTrace();

}

Systemoutprintln("启动"+thisgetName()+"");

try {

sleep(3000);//等待3秒,为了测试

} catch (InterruptedException e) {

eprintStackTrace();

}

Systemoutprintln("停止"+thisgetName()+"");

ThreadTestnotifyThread();

}

}

一个正确的答案取决于你实际使用QThread的方式以及你如何实现stop()

Qt中的预期用例假设以下模型:

您创建了一个对象,它将执行一些有用的工作来响应Signals

您创建一个QThread并将您的对象移动到此线程

当您向对象发送信号时,它会在您创建的QThread中处理

现在你需要了解一些实际实现方式的内部结构Qt中有几种信号"模型",在某些情况下,当您"发送信号"时,您实际上只是简单地调用"插槽"功能这是一个"直接"插槽连接,在这种情况下,slot()将在调用者线程中执行,一个引发信号因此,为了与另一个线程通信,Qt允许另一种信号"排队连接"调用者不是调用slot(),而是将消息留给拥有此插槽的对象与此对象关联的线程将读取此消息(稍后某个时间)并执行slot()本身的执行

现在,您可以了解创建和执行QThread时发生的情况新创建的线程将执行QThread :: run(),默认情况下,它将执行QThread :: exec(),但这是一个无限循环,它查找与线程关联的对象的消息并将它们传输到这些对象的插槽中调用QThread :: quit()会向此队列发送终止消息当QThread :: exec()读取它时,它将停止进一步处理事件,退出无限循环并轻轻终止线程

现在,正如您可能猜到的,为了接收终止消息,必须满足两个条件:

你应该运行QThread :: exec()

您应该退出当前正在运行的插槽

当人们从QThread继承并使用他们自己的代码覆盖QThread :: run时,通常会违反第一个在大多数情况下,这是错误的用法,但它仍然被广泛传授和使用在你的情况下,似乎你违反了第二个要求:你的代码运行无限循环,因此QThread :: exec()根本没有得到控件,也没有机会检查它是否需要退出将你的无限循环丢弃到回收站,QThread :: exec()已经为你运行了这样的循环想一想如何重新编写代码,使其不运行无限循环,这总是可行的根据"消息到线程"概念来考虑您的程序如果您定期检查某些内容,请创建一个QTimer,它将向您的对象发送消息并在您的插槽中执行检查如果处理大量数据,请将此数据拆分为较小的块并编写对象,以便一次处理一个块以响应某些消息例如,如果您逐行处理图像,请创建一个槽processLine(int line)并将信号序列"0,1,2 height-1"发送到该槽请注意,一旦完成处理,您还必须显式调用QThread :: quit(),因为事件循环是无限的,当您处理图像的所有行时它不会"知道"还要考虑将QtConcurrent用于QThread的计算密集型任务

现在,QThread :: terminate()确实以一种非常不同的方式停止一个线程它只是要求OS杀死你的线程 *** 作系统会简单地将您的线程突然停在代码中的任意位置线程堆栈内存将是空闲的,但此堆栈指向的任何内存都不会如果一个线程拥有某些资源(例如文件或互斥),它将不会释放它涉及将数据写入存储器的 *** 作可以在中间停止并且使存储器块(例如,对象)不完全填充并且处于无效状态正如你可能从这个描述中猜到的那样,你永远不应该调用:: terminate(),除非极少数情况下保持线程运行比获取内存和资源泄漏更糟糕

以上就是关于C++代码中去除和Qt相关的代码全部的内容,包括:C++代码中去除和Qt相关的代码、qthread wait 阻塞哪个线程、qthread中收不到readyread信号等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9446687.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存