从pthread发送信号到QObject

时间:2014-01-15 10:16:29

标签: c qt pthreads signals qtextedit

我会尽量明确。我创建了一个Qt应用程序,它有一些按钮和一个QTextEdit。接下来我创建一个pthread。并提供指向MainWindow的指针作为参数。像这样:

MainWindow w;
pthread_create(&rThread,NULL,treat,&w);

treat是创建线程时执行的函数。现在,如果我有一个名为myButton的pushButton,我会在treat函数中做这样的事情:

 void *treat(void *arg)
 {
  MainWindow *win = (MainWindow*)arg;
  win->ui->myButton->setEnabled(false);
  close(pthread_self());
 }

它会正常工作,我的应用程序中的myButton将会禁用。但是,如果我做这样的事情:

 void *treat(void *arg)
 {
  MainWindow *win = (MainWindow*arg;
  win->ui->editText->setText("random string");
  close(pthread_self());
 }

我的应用程序将崩溃并出现以下错误:

  

QObject:无法为不同的父级创建子级   线。 (Parent是QTextDocument(0x23af2e0),父亲的主题是   QThread(0x209a290),当前线程为QThread(0x7f7eec000af0)   程序意外地完成了。

据我所知,Ui生活在主线程中,并且可能在我创建的线程中不可访问,尽管事实上我提供了主窗口的指针到这个线程。但为什么禁用该按钮有效?我很迷茫。我使用QThread的原因是因为我们的老师告诉我不要这样做。我必须使用pthreads。我如何将这样的更改从pthread应用到editText? 我怎么能从一个pthread发送一个信号到Ui“生活”的另一个线程。先谢谢你们。

2 个答案:

答案 0 :(得分:3)

一般来说,从QObject以外的线程调用任何object->thread()(或派生类)方法是错误的 - 除非它们被设计和记录到是线程安全的。 Qt中有一些方法明确记录为线程安全,例如QCoreApplication::postEvent

您面临的行为是由于从非gui线程访问QWidget方法。它是未定义的行为,因此某些方法可能会崩溃,有些方法可能会崩溃,但即使它们不存在,它仍然是未定义的行为,您无法指望它。我们所知道的,这可能取决于月亮的相位。

另一个线程唯一安全的做法是将事件发布到对象。当您在另一个线程中的对象上使用QMetaMethod::invokeQMetaObject::invokeMethod时,Qt会在内部将QMetaCallEvent发布到该对象。由于发布事件是线程安全的(可以从其他线程完成),因此可以使用其他线程中的任何一种调用方法。 QObject::event()通过执行适当的方法调用来对此类事件做出反应。

所以,你可以从另一个线程做的唯一事情是:

QMetaObject::invokeMethod(win->ui->editText, "setText", Q_ARG(QString, "random string"));

唉,这是糟糕的设计,因为你将MainWindow的内部细节(如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可用时不使用pthread。

答案 1 :(得分:1)

首先在没有必要时混合库是坏习惯。 Qt提供了QThread,非常方便QtConcurrent

其次这是糟糕的设计。创建一些QObject将在线程中处理你的计算,并在将结果传递给UI(主线程)时发出信号。然后创建连接,Qt将处理其余的东西使其线程安全(默认情况下,如果信号在线程之间传递,它将排队连接)。

你的Qt并发代码:

void *treat(SomeClass *arg) {
    arg->doStuff();
}

QtConcurrent::run(treat, someObject);