Abh*_*yal 6 c++ linux qt multithreading c++11
我已经阅读了许多 stackoverflow 的答案和一些博客文章(也包括 QThread 文档),但我仍然不确定如何在 QThreads 仍在运行时处理退出的主应用程序(同时不会使应用程序崩溃)。使这变得困难的是,这些 QThread 实例包含不同类型的阻塞函数,例如 curl 查询、c++ 文件 io 等。这使得使用 isInterruption 请求的 API 变得困难(我会在理想情况下使用)。最重要的是,我必须确保它们在 Linux、Windows 和 OSX 上都能正常工作。我们可以在这里假设任何文件 io 损坏或不完整的网络查询都不会让我们担心并且会得到处理。这是压缩的整个工作示例。我以两种不同的方式使用 Qthreads,我将在这里演示,aboutToQuit()线程terminate()假设这是安全的,因为应用程序无论如何都会关闭 -
工人/控制器
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString &msg) { QThread::sleep(10); emit resultReady("Finished"); } // simulates thread doing work
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(terminateThread()));
workerThread.start();
}
~Controller() { workerThread.quit(); workerThread.wait(); }
public slots:
void handleResults(const QString &msg);
void terminateThread() { workerThread.terminate(); workerThread.wait(); }
signals:
void operate(const QString &msg);
};
// can be started like
Controller c;
emit c.operate("Starting Thread");
Run Code Online (Sandbox Code Playgroud)
方法 run() 覆盖
class WorkerThread : public QThread
{
Q_OBJECT
void run() override { QThread::sleep(10); emit resultReady("Finished");}
signals:
void resultReady(const QString &s);
public slots:
void terminateThread() { workerThread.terminate(); workerThread.wait(); }
};
class MyObject : public QObject {
Q_OBJECT
public slots:
void handleResults(const QString &msg);
public:
void startWorkInAThread() {
WorkerThread *workerThread = new WorkerThread();
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), workerThread, SLOT(terminateThread()));
workerThread->start();
}
};
// can be started like
MyObject obj;
obj.startWorkInAThread();
Run Code Online (Sandbox Code Playgroud)
我使用 main() 测试这两种方法,看起来像 -
QCoreApplication a(argc, argv);
std::puts("Starting app");
// Controller c;
// emit c.operate("Starting Thread");
MyObject obj;
obj.startWorkInAThread();
QTimer::singleShot(2000, [&]{
std::puts("Quit pressed");
a.quit();
});
return a.exec();
Run Code Online (Sandbox Code Playgroud)
现在的问题——
如果我使用 Controller 方法,Linux 会给出一些关于退出时未捕获异常的错误消息。如果我删除 .wait() 调用,该消息就会消失,但这些调用是必要的。Windows 退出正常,但返回代码是一些负的大数。OSX 使应用程序崩溃,可能是由于 .wait() 调用。
Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt.
You must not let any exception whatsoever propagate through Qt code.
If that is not possible, in Qt 5 you must at least reimplement
QCoreApplication::notify() and catch all exceptions there.
(process:3416): GLib-CRITICAL **: 22:45:51.656: g_source_unref_internal: assertion 'source != NULL' failed
Run Code Online (Sandbox Code Playgroud)
如果我使用 run() 覆盖,Linux 工作得很好,OSX 也是如此。在 Windows 上,程序永远不会完成,停留在 .terminate() 调用上,或者如果我删除它然后在 .wait() 调用上。
还有一些用法(在实际应用程序中,而不是在给定的示例中),其中使用了 run() 覆盖,但 run 方法的所有者类被初始化为 -WorkerThread *workerThread = new WorkerThread(this);由于this被设置为父类,它会在退出时以某种方式崩溃程序。
我实际上不想等待线程并希望它们在我的程序退出时尽快退出,一些阻塞的网络操作可能需要几分钟才能完成。
我想我已经详细解释了所有内容,但总而言之,我希望我的应用程序在运行后台线程时优雅地退出并且根本不会崩溃。并在所有支持(提及)的 QT 平台上执行此操作。
| 归档时间: |
|
| 查看次数: |
247 次 |
| 最近记录: |