从pthread向QObject发送信号
我会尽量说清楚的。我创建了一个Qt应用程序,它有一些按钮和一个QTextEdit。接下来我创建一个pthread。并提供指向主窗口的指针作为参数。大概是这样的:从pthread向QObject发送信号,c,qt,pthreads,signals,qtextedit,C,Qt,Pthreads,Signals,Qtextedit,我会尽量说清楚的。我创建了一个Qt应用程序,它有一些按钮和一个QTextEdit。接下来我创建一个pthread。并提供指向主窗口的指针作为参数。大概是这样的: MainWindow w; pthread_create(&rThread,NULL,treat,&w); void *treat(void *arg) { MainWindow *win = (MainWindow*arg; win->ui->editText->setText("ran
MainWindow w;
pthread_create(&rThread,NULL,treat,&w);
void *treat(void *arg)
{
MainWindow *win = (MainWindow*arg;
win->ui->editText->setText("random string");
close(pthread_self());
}
treat是创建线程时执行的函数。现在,如果我有一个名为myButton的按钮,我在treat函数中执行类似的操作:
void *treat(void *arg)
{
MainWindow *win = (MainWindow*)arg;
win->ui->myButton->setEnabled(false);
close(pthread_self());
}
它将正常工作,我的应用程序中的myButton将禁用。但是,如果我这样做:
MainWindow w;
pthread_create(&rThread,NULL,treat,&w);
void *treat(void *arg)
{
MainWindow *win = (MainWindow*arg;
win->ui->editText->setText("random string");
close(pthread_self());
}
我的应用程序将因以下错误而崩溃:
QObject:无法为处于不同位置的父级创建子级
线(父线程是QTextDocument(0x23af2e0),父线程是
QThread(0x209a290),当前线程是QThread(0x7f7eec000af0)的
程序意外地完成了
据我所知,Ui位于主线程中,尽管我提供了指向该线程的主窗口指针,但在我创建的线程中可能无法访问。但是为什么禁用按钮会起作用呢?我非常困惑。我之所以不使用QThread,是因为我们的老师告诉我不要这样做。我必须这样做使用pthread。如何将pthread的更改应用于editText?
我怎样才能从一个pthread向另一个线程发送一个信号,在这个线程中,Ui是“活动的”。提前感谢各位。首先,在不需要的时候混合库是一个坏习惯。Qt提供了
QThread
和非常方便的QtConcurrent
其次,这是一个糟糕的设计。创建一些QObject
,它将在线程中处理您的计算,并在将结果传递给UI(主线程)时发出信号。然后创建连接,Qt将处理其余内容,使其线程安全(默认情况下,如果信号在线程之间传递,它将排队连接)
您的Qt并发代码:
void *treat(SomeClass *arg) {
arg->doStuff();
}
QtConcurrent::run(treat, someObject);
首先,在不必要的时候混合库是一个坏习惯。Qt提供了
QThread
和非常方便的QtConcurrent
其次,这是一个糟糕的设计。创建一些QObject
,它将在线程中处理您的计算,并在将结果传递给UI(主线程)时发出信号。然后创建连接,Qt将处理其余内容,使其线程安全(默认情况下,如果信号在线程之间传递,它将排队连接)
您的Qt并发代码:
void *treat(SomeClass *arg) {
arg->doStuff();
}
QtConcurrent::run(treat, someObject);
一般来说,从非
object->thread()的线程调用任何QObject
(或派生类)方法都是错误的
-除非它们的设计和文档记录是线程安全的。Qt中有一些方法明确记录为线程安全的,例如QCoreApplication::postEvent
您面临的行为是由于从非gui线程访问QWidget
方法。这是未定义的行为,因此有些方法可能会崩溃,有些不会,但即使它们没有崩溃,您也无法依赖未定义的行为。据我们所知,这可能取决于月亮的相位
从另一个线程执行的唯一安全操作是向对象发布事件。当您在另一个线程的对象上使用QMetaMethod::invoke
或QMetaObject::invokeMethod
时,Qt将在内部向对象发布QMetaCallEvent
。因为发布事件是线程安全的(可以从其他线程执行),则可以从其他线程使用这些调用方法中的任何一个。QObject::event()
通过执行适当的方法调用来对此类事件作出反应
因此,您可以从另一个线程执行的唯一操作是:
QMetaObject::invokeMethod(win->ui->editText, "setText", Q_ARG(QString, "random string"));
唉,这是一个糟糕的设计,因为您将主窗口的内部细节(如ui
指针)暴露给外部。您应该做的是在窗口上设置一个setEditText
插槽:
MainWindow : public QWidget {
...
public:
Q_SLOT void setEditText(const QString & str) {
ui->editText->setText(str);
}
...
};
然后,从另一个线程执行以下操作:
QMetaObject::invokeMethod(win, "setEditText", Q_ARG(QString, "random string"));
我完全同意Marek R的建议,当您有可用的
QThread
时,不要使用pthreads。一般来说,从object->thread()以外的线程调用任何QObject
(或派生类)方法都是错误的
-除非它们的设计和文档记录是线程安全的。Qt中有一些方法明确记录为线程安全的,例如QCoreApplication::postEvent
您面临的行为是由于从非gui线程访问QWidget
方法。这是未定义的行为,因此有些方法可能会崩溃,有些不会,但即使它们没有崩溃,您也无法依赖未定义的行为。据我们所知,这可能取决于月亮的相位
从另一个线程执行的唯一安全操作是向对象发布事件。当您在另一个线程的对象上使用QMetaMethod::invoke
或QMetaObject::invokeMethod
时,Qt将在内部向对象发布QMetaCallEvent
。因为发布事件是线程安全的(可以从其他线程执行),则可以从其他线程使用这些调用方法中的任何一个。QObject::event()
通过执行适当的方法调用来对此类事件作出反应
因此,您可以从另一个线程执行的唯一操作是:
QMetaObject::invokeMethod(win->ui->editText, "setText", Q_ARG(QString, "random string"));
唉,这是一个糟糕的设计,因为您将主窗口的内部细节(如ui
指针)暴露给外部。您应该做的是在窗口上设置一个setEditText
插槽:
MainWindow : public QWidget {
...
public:
Q_SLOT void setEditText(const QString & str) {
ui->editText->setText(str);
}
...
};
然后,从另一个线程执行以下操作:
QMetaObject::invokeMethod(win, "setEditText", Q_ARG(QString, "random string"));
我完全同意Marek R的建议,当您有可用的
QThread
时,不要使用pthreads。因此,我必须创建一个新类,该类将继承QObject,并具有将发送到属于主窗口的插槽的信号。但是,我何时调用connect方法?在线程启动之前?或者我可以在内部执行该操作e处理功能?如果您懒惰,您可以向main窗口添加信号