Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从pthread向QObject发送信号_C_Qt_Pthreads_Signals_Qtextedit - Fatal编程技术网

从pthread向QObject发送信号

从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

我会尽量说清楚的。我创建了一个Qt应用程序,它有一些按钮和一个QTextEdit。接下来我创建一个pthread。并提供指向主窗口的指针作为参数。大概是这样的:

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窗口添加信号