我遇到问题,在QThread
对象上调用quit后,没有收到剩余的发送信号。
该方案包含2个额外的线程(QThread
和std::thread
)和主执行线程。我们打电话给QThread
Q
,std::thread
T
和主线M
。
在M
我创建了Q
,R
中的接收者对象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发现的其他一些东西,但到目前为止还没有提案。
答案 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();