由于其他线程忙于大循环,QTimer 延迟触发
QTimer fires late due other thread busy with big loop
环境简介:
我有一台运行用 qt 编写的应用程序的设备。它有一个处理数据库操作(SQlite)的主线程和一个用于网络操作(通过 3G)的单独线程。
主线程事件循环是 运行 by QCoreApplication::exec,另一个处理网络操作的线程是 运行 by QThread::exec。顺便说一句,套接字线程亲和力在启动后会发生变化(例如,moveToThread(socketThreadPtr))
问题简介:
主线程忙于循环,以便 select 从数据库中获取大约 10k 条记录,该循环大约需要 +30 秒。在网络线程中有一个 15 秒的计时器,每次到期都必须发送一条保持活动消息。问题是 timeout() 信号的插槽仅在循环完成后才执行。
解决方案建立至今(但不满意):
如果我在记录 select 的循环中调用 QCoreApplication::processEvents,问题就解决了,但我想知道是否存在解决方案而不是此解决方法。
备注:
定时器、信号和插槽,它们给出了发送保持活动消息的命令,目前在主线程中处理(但 read/write 发生在网络线程中)。另外,我在网络线程上移动了计时器,但得到的结果与在主线程上的结果相同。
你必须在你的网络线程中创建定时器,也许Qtimer是网络线程的成员,所以网络线程将在主线程和它的子线程的线程亲和中构建
设置为主线程,接下来你已经将网络线程移动到新的Qthread,但是Qtimer呢?它仍然存在于主线程中(除非您明确定义网络 class 作为其父线程,因此正如您所说的 moveToThread 将影响对象的子线程以及 Qtimer)
Qtimer应该在网络线程中构建,您可以在其中一个网络线程槽中构建一个新的Qtimer并将其连接到Qthread::start信号。因此,通过调用 Qthrad 的 start 方法,您的插槽将在新线程上执行,并且 Qtimer 将分别在该线程上构建。
考虑到您的主线程是服务器并且客户端应该在线程中处理,这样的事情实际上应该在您的专用线程中创建套接字和计时器。否则只需在初始化函数中使用 QTcpSocket::connectToHost()
或 QTcpServer:::bind()
。
主线程:
auto t = new QThread();
t->start();
auto o = new MyThreadObject();
o.moveToThread(t);
o.setDescriptor(socketDesc);
QMetaObject::invokeMethod(o, "initialize", Qt::QueuedConnection);
我的线程对象:
class MyThreadObject : public QObject
{
Q_OBJECT
public:
MyThreadObject(){...};
void setDescriptor(qintptr socketdescriptor)
{
m_desc = socketdescriptor;
}
public slots:
void initialize()
{
m_tcpSocket = new QTcpSocket();
m_tcpSocket->setSocketDescriptor(m_desc);
//socket configuration
m_timer = new QTimer();
//timer configuration
m_timer->start();
}
private:
QTcpSocket* m_tcpSocket;
QTimer* m_timer;
qintptr m_desc;
}
环境简介: 我有一台运行用 qt 编写的应用程序的设备。它有一个处理数据库操作(SQlite)的主线程和一个用于网络操作(通过 3G)的单独线程。 主线程事件循环是 运行 by QCoreApplication::exec,另一个处理网络操作的线程是 运行 by QThread::exec。顺便说一句,套接字线程亲和力在启动后会发生变化(例如,moveToThread(socketThreadPtr))
问题简介: 主线程忙于循环,以便 select 从数据库中获取大约 10k 条记录,该循环大约需要 +30 秒。在网络线程中有一个 15 秒的计时器,每次到期都必须发送一条保持活动消息。问题是 timeout() 信号的插槽仅在循环完成后才执行。
解决方案建立至今(但不满意): 如果我在记录 select 的循环中调用 QCoreApplication::processEvents,问题就解决了,但我想知道是否存在解决方案而不是此解决方法。
备注: 定时器、信号和插槽,它们给出了发送保持活动消息的命令,目前在主线程中处理(但 read/write 发生在网络线程中)。另外,我在网络线程上移动了计时器,但得到的结果与在主线程上的结果相同。
你必须在你的网络线程中创建定时器,也许Qtimer是网络线程的成员,所以网络线程将在主线程和它的子线程的线程亲和中构建 设置为主线程,接下来你已经将网络线程移动到新的Qthread,但是Qtimer呢?它仍然存在于主线程中(除非您明确定义网络 class 作为其父线程,因此正如您所说的 moveToThread 将影响对象的子线程以及 Qtimer)
Qtimer应该在网络线程中构建,您可以在其中一个网络线程槽中构建一个新的Qtimer并将其连接到Qthread::start信号。因此,通过调用 Qthrad 的 start 方法,您的插槽将在新线程上执行,并且 Qtimer 将分别在该线程上构建。
考虑到您的主线程是服务器并且客户端应该在线程中处理,这样的事情实际上应该在您的专用线程中创建套接字和计时器。否则只需在初始化函数中使用 QTcpSocket::connectToHost()
或 QTcpServer:::bind()
。
主线程:
auto t = new QThread();
t->start();
auto o = new MyThreadObject();
o.moveToThread(t);
o.setDescriptor(socketDesc);
QMetaObject::invokeMethod(o, "initialize", Qt::QueuedConnection);
我的线程对象:
class MyThreadObject : public QObject
{
Q_OBJECT
public:
MyThreadObject(){...};
void setDescriptor(qintptr socketdescriptor)
{
m_desc = socketdescriptor;
}
public slots:
void initialize()
{
m_tcpSocket = new QTcpSocket();
m_tcpSocket->setSocketDescriptor(m_desc);
//socket configuration
m_timer = new QTimer();
//timer configuration
m_timer->start();
}
private:
QTcpSocket* m_tcpSocket;
QTimer* m_timer;
qintptr m_desc;
}