إشارات QT عبر المواضيع ، واحد هو موضوع واجهة المستخدم الرسومية؟

StackOverflow https://stackoverflow.com/questions/2086142

سؤال

ماذا يعني نقل كائن من مؤشر ترابط إلى آخر في QT باستخدام MovetOthRead؟ يبدو أن كل شيء يعمل حتى قبل استخدام MovetOthRead ، والذي يحرك الكائن من مؤشر ترابط واحد (مؤشر ترابط GUI) إلى مؤشر ترابط آخر (عمل) و qt: توصيل يستدعي الفتحة المناسبة على الكائن.

هل هناك أي اختلاف بسبب المكان الذي يعيش فيه الكائن أو موضوع واجهة المستخدم الرسومية أو موضوع العامل؟

تحرير: لقد صنعت برنامجًا صغيرًا ، لكنني لا أفهم كيف يعمل QTREAD مع وظيفة الإشارة والفتحة ، وسأكون ممتناً إذا تمكنت

#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    QHBoxLayout * pH = new QHBoxLayout(&w);
    QPushButton * pushButton = new QPushButton("asdad");
    QLineEdit * lineEdit = new QLineEdit("AAA");
    pH->addWidget(pushButton);
    pH->addWidget(lineEdit);
    w.setLayout(pH);
    w.show();
    MyThread thread;
    qDebug("Thread id %d",(int)QThread::currentThreadId());
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ;
    QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)));
    return a.exec();
}

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();
public slots:
    void callRun();
    void run();
 signals:
    void signalGUI(QString);
private:
    QMutex mutex;

};

#endif // MYTHREAD_H


#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>

MyThread::MyThread()
{
}
 void MyThread::callRun()
 {

     qDebug("in thread");
    if(!isRunning())
     {
        this->start(LowestPriority);
        exec();
    }
    else
    {
        run();
    }

 }
 void MyThread::run()
 {
     QMutexLocker fn_scope(&mutex);
     static int a = 0;
    ++a;
     qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
     this->sleep(3);
     static QString number;
     QString temp;
     number += temp.setNum(a);
     emit signalGUI(number);
 }
هل كانت مفيدة؟

المحلول

ألق نظرة على الإشارات والفتحات عبر المواضيع. إذا كنت تستخدم دائمًا الإشارات والفتحات للتواصل مع مؤشر ترابط العمال ، فإن QT تعالج MovetOthRead لك إذا كان هناك حاجة واستخدمت الاتصال الصحيح.

تحرير: أعتقد أن مؤلف المقال كان يرى مشكلته منذ أن كان يتصل بالبدء في المنشئ قبل إنشاء الخيط بالفعل. بمعنى آخر ، لا تثق في رمز الطرف الثالث بشكل أعمى.

تحرير: ردًا على تعليقك ، انظر إلى ماندلبروت مثال ، تحت MandelbrotWidget Class Implementation رأس:

مع اتصالات قائمة الانتظار ، يجب على QT تخزين نسخة من الحجج التي تم تمريرها إلى الإشارة حتى تتمكن من تمريرها إلى الفتحة لاحقًا. يعرف QT كيفية أخذ نسخة من العديد من أنواع C ++ و QT ، لكن Qimage ليس أحدها. لذلك يجب أن نسمي وظيفة القالب qregisterMetAtyPe () قبل أن نتمكن من استخدام Qimage كمعلمة في الاتصالات في قائمة الانتظار.

أعتقد أن هذا قديم قليلاً ، وهنا أنواع ميتا صالحة. نظرًا لأن الإشارات والفتحات عبر المواضيع تستخدم اتصالات قائمة الانتظار ، يجب ألا تضطر إلى إجراء مكالمات MovetOthRead في معظم الحالات.

تحرير: سأحاول شرح الأشياء بمثال مماثل:

mythread.h:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
   Q_OBJECT

protected:
   virtual void run();

signals:
   void signalGUI(QString);
};

#endif // MYTHREAD_H

mythread.cpp:

#include "mythread.h"
#include <QString>

void MyThread::run()
{
   qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
   static int run = 0;
   QString temp = QString("Run: %1").arg(run++);
   qDebug("String address inside run %p", &temp);
   emit signalGUI(temp);
}

myLineEdit.H

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H

#include <QLineEdit>

class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
    explicit MyLineEdit(QWidget *parent = 0);

public slots:
    void setText(const QString &string);

};

#endif // MYLINEEDIT_H

myLineEdit.cpp

#include "mylineedit.h"
#include <QThread>

MyLineEdit::MyLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
}

void MyLineEdit::setText(const QString &string)
{
   qDebug("Thread id inside setText %d",(int)QThread::currentThreadId());
   qDebug("String address inside setText %p\n", &string);
   QLineEdit::setText(string);
}

main.cpp:

#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include "mythread.h"
#include "mylineedit.h"

//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QWidget w;
   QHBoxLayout * pH = new QHBoxLayout(&w);
   QPushButton * pushButton = new QPushButton("Run Thread", &w);
   MyLineEdit * lineEdit = new MyLineEdit(&w);

   pH->addWidget(pushButton);
   pH->addWidget(lineEdit);
   w.show();

   MyThread thread;
   qDebug("Thread id %d",(int)QThread::currentThreadId());
   QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(start())) ;
   QObject::connect(&thread,SIGNAL(signalGUI(const QString&)),lineEdit,SLOT(setText(const QString&)));
   return a.exec();
}

عينة الإخراج بعد النقر فوق الزر:

Thread id 1088110320
Thread id inside run 1093176208
String address inside run 0x41288350
Thread id inside setText 1088110320
String address inside setText 0x974af58

كما ترون ، يختلف موضوع التشغيل عن موضوع واجهة المستخدم الرسومية الرئيسية. أيضًا ، على الرغم من أنك تمرر إشارة إلى QString ، لأنه يعبر حدود الخيوط ، فإنه ينسخها. أنا بقوة شجعك على القراءة المواضيع و qobject.

نصائح أخرى

  1. ال QThread::start() الطريقة تنشئ الموضوع ويدعو run() التنفيذ. إذا كنت ترغب في التعامل مع الأحداث أو استلام الإشارات على الموضوع الذي عليك الاتصال به QThread::exec() داخل لك run() التنفيذ. يجب ألا تتصل أبدا run() صراحة ويجب ألا تتصل أبدا exec() خارج run().

  2. يفرد مؤشر ترابط المالك فرقًا فقط عند توصيل الفتحة بإشارة بنوع الاتصال بخلاف ذلك Qt::DirectConnection. ثم ستضمن QT أن يتم تشغيل الفتحة على موضوع المالك ، ولكن يجب أن يقوم مؤشر ترابط المالك بتشغيل حلقة حدث مع QThread::exec(). في هذه الحالة دعوة myObj.moveToThread(myThread) سيضمن ذلك myObj يتم تشغيل الفتحات على الموضوع myThread.

  3. ينتمي كائن مؤشر الترابط إلى مؤشر الترابط حيث تم إنشاؤه ، وليس على الخيط الذي يديره (وحيث سيتم تشغيل طريقة التشغيل). لذلك عندما تقوم بتوصيل إشارة إلى فتحة كائن مؤشر ترابط ، سيتم تشغيل تلك الفتحة في مؤشر الترابط حيث تم إنشاء كائن مؤشر الترابط ما لم تتصل moveToThread().

عند تحريك كائن بين مؤشرات الترابط ، يمكنك تحديد حلقة الحدث التي تنتمي إليها. عند إجراء اتصالات داخل مؤشر ترابط ، يستدعي رمز الإشارة مباشرة كل واحدة من الفتحات (الحاجة إلى الانتظار حتى ينتهي). تضع الإشارة عبر حدود مؤشر الترابط استدعاء الإشارة على حلقة الحدث ، مما يسمح لخيط الفتحة بإجراء المكالمة إلى الفتحة عندما تكون جاهزة.

يتطلب منك إجراء مكالمات مباشرة بين المواضيع التأكد من إعادة إدخال وظائفك. يجب عليك أيضًا التأكد من حماية بياناتك باستخدام Mutexes أو Semaphores وفي الوقت نفسه تجنب ظروف السباق.

في المقالة ، أعتقد أن التأخير يرجع إلى أن يكون الدعوة مباشرة ، أي لم تتم معالجته على الإطلاق في الخلفية (لكنني فقط قشط النص).

#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    QHBoxLayout * pH = new QHBoxLayout(&w);
    QPushButton * pushButton = new QPushButton("asdad");
    QLineEdit * lineEdit = new QLineEdit("AAA");
    pH->addWidget(pushButton);
    pH->addWidget(lineEdit);
    w.setLayout(pH);
    w.show();
    MyThread thread;
    thread.moveToThread(&thread);
    thread.start();
    qDebug("Thread id %d",(int)QThread::currentThreadId());
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun()),Qt::QueuedConnection) ;
    QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)),Qt::DirectConnection);
    return a.exec();
}

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();
public slots:
    void callRun();
    void run();
 signals:
    void signalGUI(QString);
private:
    QMutex mutex;

};

#endif // MYTHREAD_H
#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>

MyThread::MyThread()
{
}
 void MyThread::callRun()
 {
     QMutexLocker fn_scope(&mutex);
     static int a = 0;
    ++a;
     qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
     this->sleep(3);
     static QString number;
     QString temp;
     number += temp.setNum(a);
     emit signalGUI(number);

 }
 void MyThread::run()
 {
    exec();
 }

يتم إنشاء كائن مؤشر ترابط جديد ويتم نقل كائن مؤشر الترابط إلى نفس الخيط. الإشارات الآن عبر مؤشرات الترابط ونوع الاتصال كلاهما قائمة انتظار ويعمل كما هو متوقع.

يمكن استخدام بعض الكائنات فقط على موضوع المالك. على سبيل المثال ، إذا قمت بإنشاء كائن ومقبس في مؤشر ترابط واحد وتريد إرسال البيانات و RECV في مؤشر ترابط آخر ، فلا يمكن ذلك. لذلك فإن أحد الحلول هو نقل كائنك من مؤشر ترابط إلى آخر والعمل عليه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top