详解 Qt 线程间共享数据(用信号槽方式)

使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。

Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容。Qt线程间共享数据主要有两种方式:

使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的;

使用singal/slot机制,把数据从一个线程传递到另外一个线程。

第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一下这种方式:

在线程之间传递signal与在一个线程内传递signal是不一样的。在一个线程内传递signal时,emit语句会直接调用所有连接的slot并等待到所有slot被处理完;在线程之间传递signal时,slot会被放到队列中(queue),而emit这个signal后会马上返回;默认情况,线程之间使用queue机制,而线程内使用direct机制,但在connect中可以改变这些默认的机制。

  1 view plaincopy to clipboardprint?    2 //TextDevice.h      3 #ifndef TEXTDEVICE_H      4 #define TEXTDEVICE_H      5 #include <QThread>      6 #include <QString>      7 #include <QMutex>       8 class TextDevice : public QThread {       9     Q_OBJECT      10 public:      11     TextDevice();      12     void run();      13     void stop();      14 public slots:      15     void write(const QString& text);      16 private:      17     int m_count;      18     QMutex m_mutex;      19 };     20 #endif // TEXTDEVICE_H      21      22      23 //TextDevice.cpp     24 #include <QMutexLocker>     25 #include <QDebug>     26 #include <QString>     27 #include "TextDevice.h"      28 TextDevice::TextDevice() {      29     m_count = 0;      30 }      31 void TextDevice::run() {      32     exec();      33 }      34 void TextDevice::stop() {      35     quit();      36 }      37 void TextDevice::write(const QString& text) {      38     QMutexLocker locker(&m_mutex);      39     qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);      40 }      41      42 //TextThread.h     43 #ifndef TEXTTHREAD_H     44 #define TEXTTHREAD_H     45 #include <QThread>     46 #include <QString>      47 class TextThread : public QThread {      48     Q_OBJECT      49 public:      50     TextThread(const QString& text);      51     void run();      52     void stop();      53 signals:      54     void writeText(const QString&);      55 private:      56     QString m_text;      57     bool m_stop;      58 };     59 #endif // TEXTTHREAD_H      60      61 //TextThread.cpp     62 #include "TextThread.h"      63 TextThread::TextThread(const QString& text) : QThread() {      64     m_text = text;      65     m_stop = false;      66 }      67 void TextThread::stop() {      68     m_stop = true;      69 }      70 void TextThread::run() {      71     while(!m_stop) {      72         emit writeText(m_text);      73         sleep(1);      74     }      75 }      76      77 //main.cpp     78 #include <QApplication>     79 #include <QMessageBox>     80 #include "TextDevice.h"     81 #include "TextThread.h"      82      83 int main(int argc, char** argv) {      84     QApplication app(argc, argv);      85     //启动线程      86     TextDevice device;      87     TextThread foo("foo"), bar("bar");      88     //把两个线程使用signal/slot连接起来      89     QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));      90     QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));      91     //启动线程      92     foo.start();      93     bar.start();      94     device.start();      95     QMessageBox::information(0, "Threading", "Close me to stop.");      96     //停止线程      97     foo.stop();      98     bar.stop();      99     device.stop();     100     //等待线程结束     101     device.wait();     102     foo.wait();     103     bar.wait();     104     return 0;     105 }    106 //TextDevice.h  107 #ifndef TEXTDEVICE_H  108 #define TEXTDEVICE_H  109 #include <QThread> 110 #include <QString> 111 #include <QMutex> 112 class TextDevice : public QThread {  113     Q_OBJECT  114 public:  115     TextDevice();  116     void run();  117     void stop();  118 public slots:  119     void write(const QString& text);  120 private:  121     int m_count;  122     QMutex m_mutex;  123 };  124 #endif // TEXTDEVICE_H  125  126  127 //TextDevice.cpp  128 #include <QMutexLocker> 129 #include <QDebug> 130 #include <QString> 131 #include "TextDevice.h"  132 TextDevice::TextDevice() {  133     m_count = 0;  134 }  135 void TextDevice::run() {  136     exec();  137 }  138 void TextDevice::stop() {  139     quit();  140 }  141 void TextDevice::write(const QString& text) {  142     QMutexLocker locker(&m_mutex);  143     qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);  144 }  145  146 //TextThread.h  147 #ifndef TEXTTHREAD_H  148 #define TEXTTHREAD_H  149 #include <QThread> 150 #include <QString> 151 class TextThread : public QThread {  152     Q_OBJECT  153 public:  154     TextThread(const QString& text);  155     void run();  156     void stop();  157 signals:  158     void writeText(const QString&);  159 private:  160     QString m_text;  161     bool m_stop;  162 };  163 #endif // TEXTTHREAD_H  164  165 //TextThread.cpp  166 #include "TextThread.h"  167 TextThread::TextThread(const QString& text) : QThread() {  168     m_text = text;  169     m_stop = false;  170 }  171 void TextThread::stop() {  172     m_stop = true;  173 }  174 void TextThread::run() {  175     while(!m_stop) {  176         emit writeText(m_text);  177         sleep(1);  178     }  179 }  180  181 //main.cpp  182 #include <QApplication> 183 #include <QMessageBox> 184 #include "TextDevice.h"  185 #include "TextThread.h"  186 int main(int argc, char** argv) {  187     QApplication app(argc, argv);  188     //启动线程  189     TextDevice device;  190     TextThread foo("foo"), bar("bar");  191     //把两个线程使用signal/slot连接起来  192     QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));  193     QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));  194     //启动线程  195     foo.start();  196     bar.start();  197     device.start();  198     QMessageBox::information(0, "Threading", "Close me to stop.");  199     //停止线程  200     foo.stop();  201     bar.stop();  202     device.stop();  203     //等待线程结束  204     device.wait();  205     foo.wait();  206     bar.wait();  207     return 0;  208 } 

  上面例子代码可以看出两个线程之间传送了类型为QString的信息。像QString等这些QT本身定义的类型,直接传送即可。但如果是自己定义的类型如果想使用signal/slot来传递的话,则没有这么简单。直接使用的话,会产生下面这种错误:

1 QObject::connect: Cannot queue arguments of type ‘TextAndNumber‘ (Make sure ‘TextAndNumber‘ is registed using qRegisterMetaType().) 

  

原因:当一个signal被放到队列中(queued)时,它的参数(arguments)也会被一起一起放到队列中(queued起来),这就意味着参数在被传送到slot之前需要被拷贝、存储在队列中(queue)中;为了能够在队列中存储这些参数(argument),Qt需要去construct、destruct、copy这些对象,而为了让Qt知道怎样去作这些事情,参数的类型需要使用qRegisterMetaType来注册(如错误提示中的说明)

步骤:(以自定义TextAndNumber类型为例)

自定一种类型,在这个类型的顶部包含:#include <QMetaType>

在类型定义完成后,加入声明:Q_DECLARE_METATYPE(TextAndNumber);

在main()函数中注册这种类型:qRegisterMetaType<TextAndNumber>("TextAndNumber");

如果还希望使用这种类型的引用,可同样要注册:qRegisterMetaType<TextAndNumber>("TextAndNumber&");

  1 view plaincopy to clipboardprint?    2 //TextAndNumber.h       3 #ifndef TEXTANDNUMBER_H       4 #define TEXTANDNUMBER_H       5 #include <QMetaType>       6 //必须包含QMetaType,否则会出现下面错误:       7 //error: expected constructor, destructor, or type conversion before ‘;’ token       8 #include <QString>       9 class TextAndNumber {      10 public:      11     TextAndNumber();      12     TextAndNumber(int, QString);      13     int count();      14     QString text();      15 private:      16     int m_count;      17     QString m_text;      18 };      19 Q_DECLARE_METATYPE(TextAndNumber);      20 #endif // TEXTANDNUMBER_H      21      22 //TextAndNumber.cpp      23 #include "TextAndNumber.h"      24 TextAndNumber::TextAndNumber() {      25 }      26 TextAndNumber::TextAndNumber(int count, QString text) {      27     m_count = count;      28     m_text = text;      29 }      30 int TextAndNumber::count() {      31     return m_count;      32 }      33 QString TextAndNumber::text() {      34     return m_text;      35 }      36      37 //TextDevice.h      38 #ifndef TEXTDEVICE_H      39 #define TEXTDEVICE_H      40 #include <QThread>      41 #include <QDebug>      42 #include <QString>      43 #include "TextAndNumber.h"      44 class TextDevice : public QThread {      45     Q_OBJECT      46 public:      47     TextDevice();      48     void run();      49     void stop();      50 public slots:      51     void write(TextAndNumber& tran);      52 private:      53     int m_count;      54 };      55 #endif // TEXTDEVICE_H      56      57 //TextDevice.cpp      58 #include "TextDevice.h"      59 TextDevice::TextDevice() : QThread() {      60     m_count = 0;      61 }      62 void TextDevice::run() {      63     exec();      64 }      65 void TextDevice::stop() {      66     quit();      67 }      68 void TextDevice::write(TextAndNumber& tran) {      69     qDebug() << QString("Call %1 (%3): %2").arg(m_count++).arg(tran.text()).arg(tran.count());      70 }      71      72 //TextThread.h      73 #ifndef TEXTTHREAD_H      74 #define TEXTTHREAD_H      75 #include <QThread>      76 #include <QString>      77 #include "TextAndNumber.h"      78 class TextThread : public QThread {      79     Q_OBJECT      80 public:      81     TextThread(const QString& text);      82     void run();      83     void stop();      84 signals:      85     void writeText(TextAndNumber& tran);      86 private:      87     QString m_text;      88     int m_count;      89     bool m_stop;      90 };      91      92 #endif // TEXTTHREAD_H      93      94 //TextThread.cpp      95 #include "TextThread.h"      96 TextThread::TextThread(const QString& text) : QThread() {      97     m_text = text;      98     m_stop = false;      99     m_count = 0;     100 }     101 void TextThread::run() {     102     while(!m_stop) {     103         TextAndNumber tn(m_count++, m_text);     104         emit writeText(tn);     105         sleep(1);     106     }     107 }     108 void TextThread::stop() {     109     m_stop = true;     110 }     111     112 //main.cpp     113 #include <QApplication>     114 #include <QMessageBox>     115 #include "TextThread.h"     116 #include "TextDevice.h"     117 #include "TextAndNumber.h"     118 int main(int argc, char *argv[])     119 {     120     QApplication app(argc, argv);     121     qRegisterMetaType<TextAndNumber>("TextAndNumber");     122     qRegisterMetaType<TextAndNumber>("TextAndNumber&");     123     TextDevice device;     124     TextThread foo("foo"), bar("bar");     125     QObject::connect(&foo, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));     126     QObject::connect(&bar, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));     127     device.start();     128     foo.start();     129     bar.start();     130     QMessageBox::information(0, "Threading", "Click me to close");     131     foo.stop();     132     bar.stop();     133     device.stop();     134     foo.wait();     135     bar.wait();     136     device.wait();     137     qDebug() << "Application end.";     138     return 0;     139 }   

  

http://www.cnblogs.com/bingcaihuang/archive/2011/07/14/2106885.html

时间: 2024-12-21 07:33:36

详解 Qt 线程间共享数据(用信号槽方式)的相关文章

详解 Qt 线程间共享数据(使用signal/slot传递数据,线程间传递信号会立刻返回,但也可通过connect改变)

使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享数据主要有两种方式: 使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的: 使用singal/slot机制,把数据从一个线程传递到另外一个线程. 第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一

线程间共享数据的一个例子

[申明:本文仅限于自我归纳总结和相互交流,有纰漏还望各位指出. 联系邮箱:[email protected]] 题目:输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值.要求时间复杂度为O(n). 题目分析: 一.如果数组中全部为负数,则返回最大负数值即可 二.当既有正数也有负数的时候: (1)从左往右叠加,如果当前叠加值小于或者等于0,则放弃,叠加总和清0(加一个负数或者0是毫无意义的),从此位置继续重新叠加 (

java多线程详解(6)-线程间的通信wait及notify方法

Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New):线程对象已经产生,但尚未被启动,所以无法执行.如通过new产生了一个线程对象后没对它调用start()函数之前.(2). 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它. 当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它

并发编程(3)线程间共享数据

一.共享内存带来的问题 读时没问题,写时会有竞争问题. 二.解决方法 1.最简单的办法就是对数据结构采用某种保护机制,确保只有进行修改的线程才能看到不变量被破坏时的中间状态.从其他访问线程的角度来看,修改不是已经完成了,就是还没开始. 2.另一个选择是对数据结构和不变量的设计进行修改,修改完的结构必须能完成一系列不可分 割的变化,也就是保证每个不变量保持稳定的状态,这就是所谓的无锁编程.另一种处理条件竞争的方式是,使用事务的方式去处理数据结构的更新.(STM) 第二种是比较高阶的内容,不在讨论范

线程间共享数据

package cn.itcast.heima2; public class MultiThreadShareData { private static ShareData1 data1 = new ShareData1(); public static void main(String[] args) { ShareData1 data2 = new ShareData1(); //第二种自定义的Runable方法,继承了Runable接口 new Thread(new MyRunnable1

JAVA 并发编程-多个线程之间共享数据(六)

多线程共享数据的方式: 1,如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做. 2,如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,例如,设计4个线程.其中两个线程每次对j增加1,另外两个线程对j每次减1,银行存取款 有两种方法来解决此类问题: 将共享数据封装成另外一个对象,然后将这个对象逐一传递给各个Runnable对象,每个线程对共享数据的操作方法也分配到那个对象身上完成,这样容易实现针对

static变量的线程间共享,进程间不共享

JAVA中通常我们会使用static域变量来在内存中缓存数据或长驻内存数据,众所周知,static是类的所有实例所共享. 考虑一个问题,假如在多线程情况下,共享数据肯定会有危险的, 例如使用SimpleDateFormat工具的一个变量时,为方便作为util写为了static,后来 在几W条数据中会出现一个奇怪的日期,这就是在多线程下会出现问题导致的数据冲突, 一般这种能私有不共享的数据最好为一个实例一份拷贝,不要做为static若非要做,就对象同步锁,使之单线程. 现在考虑的问题是,在进程间,

Java并发工具类(四):线程间交换数据的Exchanger

简介 Exchanger(交换者)是一个用于线程间协作的工具类.Exchanger用于进行线程间的数据交换.它提供一个同步点,在这个同步点两个线程可以交换彼此的数据.这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方. Exchanger的应用场景 1.Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时

详解Qt动画框架(2)--- 实现网易云音乐tag切换

在详解Qt的动画框架(一)介绍了关于Qt动画框架一些基础知识,在这一节中,将会实际的看到有关与动画框架的实现,该案例主要实现的具体是网易云音乐tag的切换,网易云音乐中的切换如图所示: 本文介绍的方法也可以达到这种切换的简易效果. 设计动画框架 首先我们需要设计对于动画框架,其需要的动画效果是什么?对于上图,我们需要的是三个tag可以不停的切换,可以抽象为左移以及右移,即一个tag从一个矩形区域,移动到另外的矩形区域,那么对于Tag的承载体选为什么较为合适呢?因为我们仅仅只需要图片的显示,因此Q