为什么在多线程中没有收到发出的信号?

时间:2017-01-11 13:41:47

标签: c++ multithreading qt c++11 qt5

我遇到问题,在QThread对象上调用quit后,没有收到剩余的发送信号。 该方案包含2个额外的线程(QThreadstd::thread)和主执行线程。我们打电话给QThread Qstd::thread T和主线M
M我创建了QR中的接收者对象Q生活在S和发件人对象std::thread。此外,如果使用T发出,则会创建S class Sender : public QObject { Q_OBJECT; public: std::vector<int> m_Sent; Sender() { } public slots: signals: void signal(int i); public: void send(int i) { m_Sent.emplace_back(i); emit signal(i); } }; class Receiver : public QObject { Q_OBJECT; public: std::vector<int> m_Received; Receiver() { } void Connect(Sender* s) { connect(s, &Sender::signal, this, &Receiver::slot, Qt::QueuedConnection); } void Disconnect(Sender* s) { disconnect(s, &Sender::signal, this, &Receiver::slot); } public slots: void slot(int i) { m_Received.emplace_back(i); } }; void main(int argc, char** argv) { QApplication app(argc, argv); qint64 random_seed = QDateTime::currentMSecsSinceEpoch(); std::cout << "Setting random seed " << random_seed << "\n"; std::srand(random_seed); std::unique_ptr<Receiver> R(new Receiver); std::unique_ptr<Sender> S(new Sender); auto actions = [&S]() { int i = 0; std::chrono::steady_clock::time_point current = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point finish = current + std::chrono::milliseconds(100); while (current < finish) { std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000)); S->send(i++); std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000)); S->send(i++); std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000)); S->send(i++); std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000)); S->send(i++); std::this_thread::sleep_until(current + std::chrono::milliseconds(17)); current = std::chrono::steady_clock::now(); } }; std::unique_ptr<QThread> Q(new QThread()); R->moveToThread(Q.get()); R->Connect(S.get()); Q->start(); std::thread T(actions); T.join(); // approach 1: QMetaObject::invokeMethod(Q.get(), "quit", Qt::QueuedConnection); Q->wait(); // never returns // approach 2: Q->quit(); Q->wait(); // missing events std::cout << "Sent: "; for(auto v : S->m_Sent) { std::cout << v << " "; } std::cout << std::endl; std::cout << "Received: "; for(auto v : R->m_Received) { std::cout << v << " "; } std::cout << std::endl; } 执行一堆。

R

我正在使用VS2013和Qt 5.5.1在Windows上工作。我用Q中的计数器测试它来跟踪接收到的信号。在调试时我经历了所有的发射,所以所有这些都应该插入到Q.wait()中的事件循环中。在Q.quit()之后,插槽的计数器与发出的信号不对应。我原本期望剩余输入事件的事件循环由Q.wait()<logger />处理,但似乎不是这样,总是从某一点开始有一个“事件流”的剪切。我现在尝试了4天通过Qt-Docu和google发现的其他一些东西,但到目前为止还没有提案。

1 个答案:

答案 0 :(得分:0)

我不是100%肯定,因为文档不是很清楚,但是什么让你认为even循环在退出前处理所有待处理的事件?我的假设是有一张支票&#34;我应该退出&#34;在每个循环中,它可以在设置退出标志时丢弃一些挂起事件。

为了总结下面的讨论,我建议添加一个新的信号,你可以从任何你想要的地方发出信号(例如,一旦你发出你想要的一切,就从std :: thread中发出)进入QThread事件循环队列并连接到QThread退出方法,以便线程在处理时退出。 如果需要,您还可以避免定义新信号。

您的代码看起来像(未经过测试):

Sender S = new Sender();
QThread Q = new QThread();
Receiver R = new Receiver();
R->moveToThread(Q);
connect(S, &Sender::signal, R, &Receiver::slot, Qt::QueuedConnection);

Q->start();
while(!Q.isRunning())
{
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

std::thread T([&S](){
    emit S->signal(); // only an example, several other connects are used too
})

T.join();

QMetaObject::invokeMethod(Q, "quit",
                          Qt::QueuedConnection);

Q.wait();