簡體   English   中英

當再次觸發信號從Qt插槽執行的功能再次被調用時,會發生什么情況?

[英]What happens when a function that is being executed from a Qt Slot is called a second time when the signal is triggered again?

這就是我的情況。

我正在寫一個TCP服務器。 該服務器將從多個客戶端獲取請求。

我有一個接收信息的類(基於名為MySocket )並對其進行緩沖,直到所有信息都到達為止。 明確地說,客戶端一旦檢測到已成功建立與我的服務器類的連接,就會發送其信息。 客戶端和服務器是在不同計算機(實際上甚至是不同的操作系統)上運行的單獨程序。

MySocket收到所有數據后,它將向服務器控制類發送qt信號。 這被接收到一個插槽中,該插槽根據其唯一參數執行許多操作。 當參數告知已接收到數據時,它將調用函數ProcessInformation 該函數需要做一些事情,所以它不是瞬時的。

如果我在服務器上收到一個新的連接請求, MySocket其保存在MySocket另一個實例中,該實例將在收到所有數據后再次發出其信號。

這是我不確定會發生什么的地方。 我相信Qt Signal-Slot系統將確保這一工作。 如果我沒記錯的話,由於slot函數尚未完成運行,第二個信號將排隊,並且我將獲得所需的行為: ProcessInformation將在其第一次運行后再次調用。 但是,我不確定,所以我問:在這種情況下,程序的行為如何? 所以我可以據此編程。

由於這是在不同計算機上運行的兩個不同程序,並且鑒於我需要測試兩個同時發送其數據的客戶端以查看其效果這一事實,所以我不確定如何測試這種情況。

由於插槽功能尚未完成運行,因此第二個信號將排隊

絕對不是。 Qt從來沒有這樣做,這是理所當然的事情。 允許信號和插槽重新進入。

行為取決於有效的連接類型

  1. Qt::DirectConnection連接就像立即通過函數指針調用一樣。 到信號返回時,插槽已完成執行。 實際上,就好像signal()的實現中簡單地包含了所有插槽調用一樣:

     signal(params) { slot(params); ... } 
  2. Qt::QueuedConnection連接就像從exec()內部通過函數指針進行調用一樣:

     signal(params) { exec.add(slot, params); ... } 

    然后execQEventLoop::execQCoreApplication::exec )執行以下操作:

     exec() { dispatchEvents(); while (!calls.empty()) calls.take_first().invoke(); } 

Qt還支持自動連接,這是默認設置,其中有效類型是在運行時在信號內確定的:

signal(params) {
   for (conn: connections)
      sameThread = conn.receiver.thread() == currentThread();
      if (conn.isDirect || (conn.isAutomatic && sameThread))
         conn.slot(params)
      else if (conn.isQueued || (conn.isAutomatic && !sameThread))
         exec.add(conn.slot, params);
}

因此,如果使用默認的自動連接類型,並且調用方和接收方處於同一線程中,則調用信號與直接在接收方對象中調用插槽是相同的。 如果調用方和接收方位於不同的線程中,則在控件返回事件循環時,調用信號將始終將要執行的調用排隊。

請注意,在Qt中,幾乎在所有情況下,只要您的代碼運行(實際上是您的任何代碼exec()exec()都位於調用堆棧上。 例如,調用堆棧可能如下所示:

MyClass::onButtonClick()    // your slot connected to a button's clicked signal
QAbstractButton::clicked()  // signal - just a C++ method (!)
QPushButton::event()        // the event handler that got the mouse event
QCoreApplication::notify()
... (platform code etc)
QAbstractEventDispatcher::processEvents()
QCoreApplication::exec()
main()
__thread_start() 

       // C runtime code

好。 因此,這與我所說的完全不同。 但是(我認為)已經足夠接近了。 這是一個只有一個按鈕即可測試我的問題的簡單Tester小部件的代碼。

標頭:

#ifndef TESTER_H
#define TESTER_H

#include <QMainWindow>
#include <QTimer>
#include <QElapsedTimer>
#include <QDebug>
#include <QTextStream>
#include <QFile>

namespace Ui {
class Tester;
}

class Tester : public QMainWindow
{
    Q_OBJECT

public:
    explicit Tester(QWidget *parent = 0);
    ~Tester();

public slots:
    void doStuff();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Tester *ui;
    QTimer timer;
    int ntimes;
    void aFunction();
};

#endif // TESTER_H

CPP:

#include "tester.h"
#include "ui_tester.h"

Tester::Tester(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Tester)
{
    ui->setupUi(this);
    ntimes = 50;
    connect(&timer,&QTimer::timeout,this,&Tester::doStuff);
}

void Tester::doStuff(){
    qWarning() << "DO STUFF";
    ntimes--;
    if (ntimes == 0) timer.stop();
    else aFunction();
}

void Tester::aFunction(){

    QFile file("output.txt");
    file.open(QFile::Append);
    QTextStream writer(&file);

    QElapsedTimer measure;
    measure.start();
    qWarning() << "AFUNCTION";
    writer << "CALL: " << ntimes << "\n";
    for (qint32 i = 0; i < 1000000; i++){
        writer << "NUM" << i << "\n";
    }
    file.close();
    qWarning() << "LASTED" << measure.elapsed();

}

Tester::~Tester()
{
    delete ui;
}

void Tester::on_pushButton_clicked()
{
    //aFunction();
    timer.start(50);
}

我的處理功能被簡單的aFunction取代,該功能將一堆數字寫入文本文件。 我使用了經過的計時器來衡量該功能完成所需的時間,平均大約需要220毫秒。

因此,使用了每50毫秒發送一次信號的計時器來代替“我的所有數據已到達”信號。 如果我是正確的,這應該重現我的問題。 當功能尚未完成執行時,信號將被發送到具有該功能的插槽。

我進行了測試,因為我們懷疑每個調用都正確地寫入了所有數字(我在輸出文件上使用grep檢查了該數字)。 指示如果信號到達尚未結束的插槽,則在上一個調用結束后立即對該插槽的調用進行排隊並調用該插槽。

我仍然感謝任何其他確認。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM