إشارات QT عبر المواضيع ، واحد هو موضوع واجهة المستخدم الرسومية؟
-
21-09-2019 - |
سؤال
ماذا يعني نقل كائن من مؤشر ترابط إلى آخر في 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.
نصائح أخرى
ال
QThread::start()
الطريقة تنشئ الموضوع ويدعوrun()
التنفيذ. إذا كنت ترغب في التعامل مع الأحداث أو استلام الإشارات على الموضوع الذي عليك الاتصال بهQThread::exec()
داخل لكrun()
التنفيذ. يجب ألا تتصل أبداrun()
صراحة ويجب ألا تتصل أبداexec()
خارجrun()
.يفرد مؤشر ترابط المالك فرقًا فقط عند توصيل الفتحة بإشارة بنوع الاتصال بخلاف ذلك
Qt::DirectConnection
. ثم ستضمن QT أن يتم تشغيل الفتحة على موضوع المالك ، ولكن يجب أن يقوم مؤشر ترابط المالك بتشغيل حلقة حدث معQThread::exec()
. في هذه الحالة دعوةmyObj.moveToThread(myThread)
سيضمن ذلكmyObj
يتم تشغيل الفتحات على الموضوعmyThread
.ينتمي كائن مؤشر الترابط إلى مؤشر الترابط حيث تم إنشاؤه ، وليس على الخيط الذي يديره (وحيث سيتم تشغيل طريقة التشغيل). لذلك عندما تقوم بتوصيل إشارة إلى فتحة كائن مؤشر ترابط ، سيتم تشغيل تلك الفتحة في مؤشر الترابط حيث تم إنشاء كائن مؤشر الترابط ما لم تتصل
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 في مؤشر ترابط آخر ، فلا يمكن ذلك. لذلك فإن أحد الحلول هو نقل كائنك من مؤشر ترابط إلى آخر والعمل عليه.