- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在下面的示例中(在 Qt GUI 应用程序中)启动了一个新线程(带有一个事件循环,我希望在其中完成一些工作):
void doWork()
{
QThread* workerThread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(started()), worker, SLOT(startWork()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
}
startWork()
可以是一个长时间运行的操作,在此期间可以关闭应用程序。
我预计只要 startWork()
在 workerThread
上执行,应用程序就不会关闭。看起来,当我关闭最后一个应用程序窗口时,workerThread
立即消失(在长时间运行的操作期间)并且应用程序关闭没有问题。
产生的问题:
workerThread
?
wait()
(最终)?
aboutToQuit()
的插槽内 wait()
并且在长时间运行的操作完成后应用程序没有关闭(设置为多于)。只有 quit(); wait();
(在提到的插槽内)允许应用程序关闭。为什么?最佳答案
QThread
基本上有一个长期存在的 API 错误:它并不总是处于可破坏状态。在 C++ 中,当可以安全调用其析构函数时,对象被认为处于可破坏状态。破坏正在运行的 QThread
是错误的。 QThread
仅仅是一个线程 Controller ,它不是“线程”本身。想一想 QFile
的行为方式:您可以随时销毁它,无论它是否打开。它真正将文件的概念封装为资源。 QThread
是围绕 native (系统)线程的包装器太薄了:当您破坏它时,它不会终止,也不会处置 native 线程(如果有的话)。这是一个资源泄漏(线程是操作系统资源),人们一遍又一遍地被这个问题绊倒。
当应用程序的 main()
函数返回时,您的 C/C++ 运行时库的实现恰好终止了应用程序的所有线程,从而有效地终止了整个应用程序。这是否是您想要的行为取决于您。您应该quit()
和wait()
您的事件循环运行线程。对于没有事件循环的线程,quit()
是空操作,您必须实现自己的退出标志。在销毁线程之前,您必须在线程上wait()
。这是为了防止竞争条件。
下面是 QThread
的安全包装器。这是一个最终类,因为您不能重新实现 run
。这很重要,因为可以通过使 quit
成为空操作的方式来完成 run 的重新实现,从而打破 contract of the class .
#include <QThread>
#include <QPointer>
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { quit(); wait(); }
};
class ThreadQuitter {
public:
typedef QList<QPointer<Thread>> List;
private:
List m_threads;
Q_DISABLE_COPY(ThreadQuitter)
public:
ThreadQuitter() {}
ThreadQuitter(const List & threads) : m_threads(threads) {}
ThreadQuitter(List && threads) : m_threads(std::move(threads)) {}
ThreadQuitter & operator<<(Thread* thread) {
m_threads << thread; return *this;
}
ThreadQuitter & operator<<(Thread& thread) {
m_threads << &thread; return *this;
}
~ThreadQuitter() {
foreach(Thread* thread, m_threads) thread->quit();
}
};
可以按如下方式使用:
#include <QCoreApplication>
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
QObject worker1, worker2;
Thread thread1, thread2;
// Style 1
ThreadQuitter quitter;
quitter << thread1 << thread2;
// Style 2
ThreadQuitter quitterB(ThreadQuitter::List() << &thread1 << &thread2);
//
worker1.moveToThread(&thread1);
worker2.moveToThread(&thread2);
thread1.start();
thread2.start();
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
return app.exec();
}
从main
返回后,线程退出器将quit()
所有工作线程。这允许线程并行结束。然后,thread2.~Thread
将等待该线程完成,然后 thread1.~Thread
将执行相同的操作。线程现在消失了,对象是无线程的并且可以安全地销毁:首先调用 worker2.~QObject
,然后调用 worker1.~QObject
。
关于c++ - 当应用程序在没有适当的 wait() 调用的情况下关闭时 QThread 会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19656442/
这段代码在 Java 中的等价物是什么?我放了一部分,我对 I/O 部分感兴趣: int fd = open(FILE_NAME, O_WRONLY); int ret = 0; if (fd =
我正在尝试将维度为 d1,d2,d3 的张量 M[a1,a2,a3] reshape 为维度为 d2, d1*d3 的矩阵 M[a2,a1*a3]。我试过 M.reshape(d2,d1*d3) 但是
我是一名优秀的程序员,十分优秀!