从c++线程发出一个信号

Qt - emit a signal from a c++ thread

本文关键字:一个 信号 c++ 线程      更新时间:2023-10-16

我想在Qt中从c++线程(std::thread)发出一个信号。

我该怎么做?

您绝对可以从线程(QThread, std::thread甚至boost::thread)发出信号。只有您必须小心连接函数的第五个参数(Qt::ConnectionType):

如果Qt::DirectConnection:槽被立即调用(从当前线程),当信号被发出。如果Qt::QueuedConnection:槽被调用时,控制返回到事件循环的接收者的线程。插槽在接收者的线程中执行。

更多选项参见ConnectionType-enum。

问题不在于你从哪个线程发出信号,而在于哪个线程调用了插槽。例如,我认为QLabel::setText必须从QLabel的所有者线程(很可能是主线程)执行。因此,如果您从一个线程发出连接到QLabelsetText的信号,则必须与Qt::AutoConnection, Qt::QueuedConnectionQt::BlockingQueuedConnection进行连接。

一般情况下,您可能不应该不小心从std::thread创建的线程发出Qt信号。参考Jpo38的回答:连接类型很重要,等等…

如果线程正在运行一些Qt事件循环,您可能可以。参见threads和QObject

有一个(可能是Unix特定的)解决方案,与Qt的Unix信号相同:使用从std::thread到主线程的管道。

但是,正如Joachim Pileborg所评论的,你应该创建自己的QThread。它是最简单的,可能是最短的(就源代码而言),你只需要复制和粘贴一些现有的例子,并使其适应你的需要。

注意,恐怕只有主线程应该做Qt GUI操作。你不应该在主线程之外使用任何QWidget(等等…)!(顺便说一句,GTK有相同的限制,至少在Linux上:只有主线程应该使用X Windows系统协议)

如果你要保持QObject的指针,那么你可以使用QMetaObject::invokeMethod成员http://qt-project.org/doc/qt-5/qmetaobject.html#invokeMethod

可能你将不得不使用Qt::QueuedConnection,这样你的信号将在适当的线程(而不是你的std::线程)被调用。请记住,您的信号不会立即被调用。

class MainForm : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainForm(QWidget *parent = nullptr);
    virtual ~MainForm();
private:
signals:
    void signalSendButtonEnable(bool);
private slots:
    void singalReceiveButtonEnable(bool);

};
MainForm::MainForm(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainForm), status_{false}, io_context_{}, timer_{io_context_}
{
    ui->setupUi(this);
    // bind SIGNAL & SLOT
    connect(this, SIGNAL(signalSendButtonEnable(bool)), this, SLOT(singalReceiveButtonEnable(bool)));
}
MainForm::~MainForm()
{
    delete ui;
}
void MainForm::singalReceiveButtonEnable(bool status){  //recv signal
    qDebug() << "singalReceiveButtonEnable";
    this->ui->btnConnect->setEnabled(status);
}
void MainForm::start(){
    std::thread t([](){
        sleep(20);
        emit signalSendButtonEnable(true);   //send signal
    });
    t.detach();
}