久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

Qt線程之間發(fā)送大量數(shù)據(jù)

Sending large amount of data between Qt threads(Qt線程之間發(fā)送大量數(shù)據(jù))
本文介紹了Qt線程之間發(fā)送大量數(shù)據(jù)的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!

問(wèn)題描述

我有一個(gè) QThread,它會(huì)定期生成大量數(shù)據(jù)(每秒幾兆字節(jié)),并且需要將其傳輸?shù)礁?(GUI) 線程.

I have a QThread which generates a fairly large amount of data regularly (couple of megabytes per second), and it needs to transmit it to the parent (GUI) thread.

恐怕我對(duì) QThread 的內(nèi)部運(yùn)作不是很確定,所以我想尋求最佳實(shí)踐.

I'm afraid I'm not that certain in the inner workings of QThread so I would like to ask for a best practice.

顯然,傳輸數(shù)據(jù)最直接的方式就是emit一個(gè)數(shù)組.然而,這有多有效?Qt是否知道它的使用位置并避免在發(fā)送和接收時(shí)進(jìn)行深度復(fù)制?

Obviously, the most direct way to transmit data is to just emit an array. However, how efficient is this? Does Qt know about where it is used and avoids deep copying it when sending and receiving it?

如果沒(méi)有,我很樂(lè)意只在主線程中分配內(nèi)存并提供一個(gè)指向子線程的指針,它將在其中寫(xiě)入數(shù)據(jù)(并且只emit關(guān)于進(jìn)度的短消息).這對(duì)我來(lái)說(shuō)似乎不是最優(yōu)雅的解決方案,這就是我問(wèn)的原因.

If not, I can gladly just allocate the memory in the main thread and give a pointer to the child thread where it will write the data (and only emit short messages about the progress). This does not seem to be the most elegant solution to me, this is why I'm asking.

如果Qt在發(fā)送和接收時(shí)避免復(fù)制多個(gè)緩沖區(qū)中的數(shù)據(jù),是否在所有系統(tǒng)中都能保證?我沒(méi)有資源嘗試在各種操作系統(tǒng)下對(duì)其進(jìn)行基準(zhǔn)測(cè)試.

If Qt avoids copying the data in multiple buffers when emitting and receiving, is it guaranteed in all systems? I don't have the resources to try benchmarking it under various OSs.

推薦答案

QThread 的內(nèi)部工作無(wú)關(guān)緊要:它們?cè)谑录h(huán)的工作方式中沒(méi)有任何作用.當(dāng)您在 QObject發(fā)出一個(gè)信號(hào),該信號(hào)位于與插槽對(duì)象不同的線程中時(shí),該信號(hào)將作為 QMetaCallEvent 發(fā)布到接收線程的事件隊(duì)列.然后,在接收線程中運(yùn)行的事件循環(huán)將對(duì)該事件執(zhí)行操作,并在連接到所發(fā)出信號(hào)的槽中執(zhí)行調(diào)用.

QThread's inner workings are irrelevant: they play no role in how the event loops work. When you emit a signal in a QObject that lives in a thread different from the slot's object, the signal will be posted as a QMetaCallEvent to the event queue of the receiving thread. The event loop running in the receiving thread will then act on this event and execute the call into the slot that was connected to the emitted signal.

因此,無(wú)論發(fā)生什么,您通過(guò)信號(hào)發(fā)送的任何數(shù)據(jù)最終都將作為 QEvent 派生類(lèi)實(shí)例中的有效負(fù)載結(jié)束.

So, no matter what happens, whatever data you send through the signal will eventually end up as a payload in an instance of QEvent-derived class.

問(wèn)題的關(guān)鍵在于當(dāng) QMetaCallEvent 到達(dá)事件循環(huán)并且容器作為參數(shù)被傳遞到槽中時(shí).當(dāng)然,復(fù)制構(gòu)造函數(shù)可以在此過(guò)程中多次調(diào)用.下面是一些簡(jiǎn)單的代碼,演示了復(fù)制構(gòu)造函數(shù)和默認(rèn)構(gòu)造函數(shù)實(shí)際上被調(diào)用了多少次

The meat of the issue is when the QMetaCallEvent reaches the event loop and the container gets passed into the slot as an argument. Of course the copy constructors could be called plenty of times along the way. Below is some simple code that demonstrates how many times the copy constructor and default constructor are in fact called

  • 關(guān)于隱式共享的寫(xiě)時(shí)復(fù)制容器 (QVector) 的數(shù)據(jù)成員的元素,

  • on the elements of the data members of an implicitly shared copy-on-write container (QVector),

在代表容器的自定義類(lèi)上.

on a custom class that stands in for a container.

你會(huì)驚喜的 :)

由于 Qt 容器是隱式共享的寫(xiě)時(shí)復(fù)制,因此它們的復(fù)制構(gòu)造成本可以忽略不計(jì):所做的只是引用計(jì)數(shù)器在構(gòu)造時(shí)自動(dòng)遞增.例如,不會(huì)復(fù)制任何數(shù)據(jù)成員.

Since Qt containers are implicitly shared copy-on-write, their copy construction has negligible cost: all that's done is a reference counter is incremented atomically on construction. None of the data members are copied, for example.

唉,11 歲之前的 C++ 顯示了它丑陋的一面:如果槽代碼以任何方式修改了容器,則無(wú)法以這種方式傳遞對(duì)槽的引用,讓編譯器知道原始容器不是不再需要了.因此:如果插槽收到對(duì)容器的 const 引用,則可以保證不會(huì)制作任何副本.如果槽接收到容器的可寫(xiě)副本并且你修改了它,將會(huì)有一個(gè)完全不必要的副本,因?yàn)檎{(diào)用站點(diǎn)上的實(shí)例不再需要.在 C++-11 中,您將傳遞一個(gè)右值引用作為參數(shù).在函數(shù)調(diào)用中傳遞右值引用會(huì)結(jié)束調(diào)用者中傳遞對(duì)象的生命周期.

Alas, pre-11 C++ shows its ugly side: if the slot code modifies the container in any way, there's no way to pass references to the slot in such a way that would let the compiler know that the original container is not needed anymore. Thus: if the slot receives a const reference to the container, you're guaranteed that no copies will be made. If the slot receives a writeable copy of the container and you modify it, there will be a completely unnecessary copy made since the instance alive at the call site is no longer needed. In C++-11 you'd pass an rvalue reference as a parameter. Passing an rvalue reference in a function call ends the lifetime of the passed object in the caller.

示例代碼輸出:

"Started" copies: 0 assignments: 0 default instances: 0 
"Created Foo" copies: 0 assignments: 0 default instances: 100 
"Created Bar" copies: 0 assignments: 0 default instances: 100 
"Received signal w/const container" copies: 0 assignments: 0 default instances: 100 
"Received signal w/copy of the container" copies: 0 assignments: 0 default instances: 100 
"Made a copy" copies: 100 assignments: 1 default instances: 101 
"Reset" copies: 0 assignments: 0 default instances: 0 
"Received signal w/const class" copies: 2 assignments: 0 default instances: 1 
"Received signal w/copy of the class" copies: 3 assignments: 0 default instances: 1 

//main.cpp
#include <QtCore>

class Class {
    static QAtomicInt m_copies;
    static QAtomicInt m_assignments;
    static QAtomicInt m_instances;
public:
    Class() { m_instances.fetchAndAddOrdered(1); }
    Class(const Class &) { m_copies.fetchAndAddOrdered(1); }
    Class & operator=(const Class &) { m_assignments.fetchAndAddOrdered(1); return *this; }
    static void dump(const QString & s = QString()) {
        qDebug() << s << "copies:" << m_copies << "assignments:" << m_assignments << "default instances:" << m_instances;
    }
    static void reset() {
        m_copies = 0;
        m_assignments = 0;
        m_instances = 0;
    }
};

QAtomicInt Class::m_instances;
QAtomicInt Class::m_copies;
QAtomicInt Class::m_assignments;

typedef QVector<Class> Vector;

Q_DECLARE_METATYPE(Vector)

class Foo : public QObject
{
    Q_OBJECT
    Vector v;
public:
    Foo() : v(100) {}
signals:
    void containerSignal(const Vector &);
    void classSignal(const Class &);
public slots:
    void sendContainer() { emit containerSignal(v); }
    void sendClass() { emit classSignal(Class()); }
};

class Bar : public QObject
{
    Q_OBJECT
public:
    Bar() {}
signals:
    void containerDone();
    void classDone();
public slots:
    void containerSlotConst(const Vector &) {
        Class::dump("Received signal w/const container");
    }
    void containerSlot(Vector v) {
        Class::dump("Received signal w/copy of the container");
        v[99] = Class();
        Class::dump("Made a copy");
        Class::reset();
        Class::dump("Reset");
        emit containerDone();
    }
    void classSlotConst(const Class &) {
        Class::dump("Received signal w/const class");
    }
    void classSlot(Class) {
        Class::dump("Received signal w/copy of the class");
        emit classDone();
        //QThread::currentThread()->quit();
    }
};

int main(int argc, char ** argv)
{
    QCoreApplication a(argc, argv);
    qRegisterMetaType<Vector>("Vector");
    qRegisterMetaType<Class>("Class");

    Class::dump("Started");
    QThread thread;
    Foo foo;
    Bar bar;
    Class::dump("Created Foo");
    bar.moveToThread(&thread);
    Class::dump("Created Bar");
    QObject::connect(&thread, SIGNAL(started()), &foo, SLOT(sendContainer()));
    QObject::connect(&foo, SIGNAL(containerSignal(Vector)), &bar, SLOT(containerSlotConst(Vector)));
    QObject::connect(&foo, SIGNAL(containerSignal(Vector)), &bar, SLOT(containerSlot(Vector)));
    QObject::connect(&bar, SIGNAL(containerDone()), &foo, SLOT(sendClass()));
    QObject::connect(&foo, SIGNAL(classSignal(Class)), &bar, SLOT(classSlotConst(Class)));
    QObject::connect(&foo, SIGNAL(classSignal(Class)), &bar, SLOT(classSlot(Class)));
    QObject::connect(&bar, SIGNAL(classDone()), &thread, SLOT(quit()));
    QObject::connect(&thread, SIGNAL(finished()), &a, SLOT(quit()));
    thread.start();
    a.exec();
    thread.wait();
}

#include "main.moc"

這篇關(guān)于Qt線程之間發(fā)送大量數(shù)據(jù)的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

【網(wǎng)站聲明】本站部分內(nèi)容來(lái)源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問(wèn)題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請(qǐng)聯(lián)系我們刪除處理,感謝您的支持!

相關(guān)文檔推薦

How can I read and manipulate CSV file data in C++?(如何在 C++ 中讀取和操作 CSV 文件數(shù)據(jù)?)
In C++ why can#39;t I write a for() loop like this: for( int i = 1, double i2 = 0; (在 C++ 中,為什么我不能像這樣編寫(xiě) for() 循環(huán): for( int i = 1, double i2 = 0;)
How does OpenMP handle nested loops?(OpenMP 如何處理嵌套循環(huán)?)
Reusing thread in loop c++(在循環(huán) C++ 中重用線程)
Precise thread sleep needed. Max 1ms error(需要精確的線程睡眠.最大 1ms 誤差)
Is there ever a need for a quot;do {...} while ( )quot; loop?(是否需要“do {...} while ()?環(huán)形?)
主站蜘蛛池模板: 国产中文字幕在线观看 | 成人影院网站ww555久久精品 | 国产91在线播放精品91 | 国产精品日韩欧美一区二区三区 | 不卡视频一区二区三区 | 亚洲成人网在线播放 | 久久最新| 免费在线毛片 | 亚洲成av| 欧美成人免费电影 | 亚洲免费视频网址 | 99re在线视频观看 | 日本视频免费观看 | 日日操日日舔 | 色婷婷综合久久久中字幕精品久久 | 国产精品免费一区二区三区四区 | h片在线播放 | 青草青草久热精品视频在线观看 | 久久久久久久久久影视 | 欧美一区二区在线观看 | 性视频网| 五月婷婷在线播放 | 中文字幕精品一区二区三区精品 | a级免费视频 | 日韩国产免费 | 祝你幸福电影在线观看 | 国产免费一二三区 | 99久久婷婷国产综合精品电影 | 国产 欧美 日韩 一区 | 国产成人精品视频在线观看 | 日韩毛片在线视频 | 久久精品国产久精国产 | 91日韩| 中文字幕一区二区视频 | 在线播放中文字幕 | 欧美二区在线 | 国产高清毛片 | 狠狠久 | 黄色精品 | 欧美毛片免费观看 | 色爱综合网 |