gpt4 book ai didi

c++ - 在 QThread::run 中间调用一个槽

转载 作者:行者123 更新时间:2023-11-28 03:15:30 25 4
gpt4 key购买 nike

我正在修改一个多线程 Qt 应用程序并且遇到了一个不可预见的行为。

我有一个从 QThread 继承的类 WorkerThread,其中的方法 run() 正在做一些工作。 WorkerThread 对象的插槽 handleSuccess() 连接到来自另一个主线程的信号,该信号是响应来自服务器的异步传入连接而发出的。据我了解,当 run() 正在运行时,流控制不在事件循环的 exec() 中,因此无法调用插槽。相反,我在应用程序的日志中看到线程正在 run() 的中间点执行它的工作,然后立即进入槽而不做任何准备。

class WorkerThread : public QThread {
Q_OBJECT
public:
WorkerThread() { moveToThread(this); /* further initialization */ }
void run();
void foo();

public slots:
void handleSuccess(const QByteArray &);
void shutdown();

private:
QMutex mutex;
MyResource resource;
volatile bool mShutdown;

/* ... other declarations */
};

void WorkerThread::foo() {
QMutexLocker locker(&mutex);
/* Working with the guarded resource */
}

void WorkerThread::run() {
QEventLoop signalWaiterEventLoop;
connect(this, SIGNAL(terminated()), &signalWaiterEventLoop, SLOT(quit()), Qt::QueuedConnection);
connect(this, SIGNAL(shutdownThread()), &signalWaiterEventLoop, SLOT(quit()), Qt::QueuedConnection);
connect(this, SIGNAL(dbChanged()), &signalWaiterEventLoop, SLOT(quit()), Qt::QueuedConnection);

while (!mShutdown) {
signalWaiterEventLoop.exec();
if (mShutdown) break;
/* ... useful payload */
foo();
/* ... another payload */
}
}


void WorkerThread::handleSuccess(const QByteArray & data) {
log(Q_FUNC_INFO, __LINE__, __FILE__);
QMutexLocker locker(&mutex);
/* processing data */
}

void WorkerThread::shutdown()
{
mShutdown = true;
emit shutdownThread();
}

对象在主线程中创建和初始化:

void SomeClass::init() {
/* ... */
mWorker = new WorkerThread();
connect(connect(mProtocol, SIGNAL(dataReceived(QByteArray)), mWorker, SLOT(processSuccess(QByteArray)),
Qt::QueuedConnection));
mWorker->start();
/* ... */
}

当从 run() 内部调用 foo() 时发生错误,锁定互斥锁,然后将流控制传递给 handleSuccess() 没有任何我看得见的原因,最后,handleSuccess() 试图锁定导致死锁的互斥锁。我会强调所有这一切都发生在一个线程中,我已经记录下来了。事实上,错误是稳定的,每次都出现在同一个地方。很明显我没有考虑到某些事情,但具体是什么?

更新我将 WorkerThread 重写为 Worker: public QObject 并且之前的 run() 变成了 public slot handleNewArrivals() ,它在线程的事件循环中被调用以响应信号。尽管如此,问题仍然存在:另一个槽正好在 handleNewArrivals() 的中间执行。中断的地方是稳定的,这里是(求evaluateTo()):

    bool hasContent = false;
QByteArray outData;
QBuffer inputBuffer(&data), outputBuffer(&outData);
inputBuffer.open(QIODevice::ReadOnly);
outputBuffer.open(QIODevice::WriteOnly|QIODevice::Append);

QXmlQuery xmlQuery;
xmlQuery.bindVariable("inputDocument", &inputBuffer);
xmlQuery.setQuery("doc($inputDocument)/commands//*");

QXmlSerializer serializer(xmlQuery, &outputBuffer);
log(Q_FUNC_INFO, __LINE__, __FILE__);
// the log line above appears, then after 1 ms the line
// from handleSuccess() appears successively.
xmlQuery.evaluateTo(&serializer);

// this line is never shown
log(Q_FUNC_INFO, __LINE__, __FILE__);
QXmlStreamReader xmlReader(outData);
while (!xmlReader.atEnd()) {
xmlReader.readNext();
if (xmlReader.tokenType() == QXmlStreamReader::Invalid) {
ufo::logT(this) << tr("Invalid token: %1").arg(xmlReader.errorString());
continue;
}

if (!xmlReader.isStartDocument() && !xmlReader.isEndDocument()) {
xmlWriterDb.writeCurrentToken(xmlReader);
hasContent = true;
}
}
ufo::logT(this) << tr("Selected data from payment, hasContent = %1").arg(hasContent?"true":"false");
inputBuffer.close();
outputBuffer.close();

QXmlQuery::evaluateTo 和 QXmlSerializer 有什么可以导致这样的跳转?似乎有异常或类似 unix 的信号(该软件在 Windows 下运行,mingw32)或其他东西,尽管包装 evaluateto() 或 try-catch 中的整个插槽没有给出任何结果。

最佳答案

我想你正被这种行为所困扰 documented for QXmlQuery :

Event Handling

When QXmlQuery accesses resources (e.g., calling fn:doc() to load a file, or accessing a device via a bound variable), the event loop is used, which means events will be processed. To avoid processing events when QXmlQuery accesses resources, create your QXmlQuery instance in a separate thread.

如果 dataReceived() 信号已排队等待 handleSuccess() 槽,当 QXmlQuery 使用事件循环时,事件将是已处理。

关于c++ - 在 QThread::run 中间调用一个槽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17030020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com