0

我已经用一些线程完成了一个应用程序。stopConsumer如果我将我的内部称为 keypressedEvent ,一切似乎都可以正常工作。但是如果我在 closeEvent 的析构函数中调用它......它会失败。

我的 QThread 类具有这样的运行方法:

void Consumer::run()
{
    forever {

        // do something something
        // do something something
        // do something something


        //-------------------------------- check for abort
        abortMutex.lock();
        if(abort) {
            abortMutex.unlock();
            qDebug() << "abort..";
            break;
        } abortMutex.unlock();
        //-------------------------------- check for abort
    }
    qDebug() << "Consumer > emit finished()";
    emit finished();
}

void Consumer::stopConsume() {
    abortMutex.lock();
    abort = true;
    abortMutex.unlock();
}

和 MainWindow 中的一个方法:

void initConsumers()
{
    consumer1 = new Consumer(....);

    connect(consumer1, SIGNAL(finished()),
            this, SLOT(deleteConsumer()));

    consumer1->start();
}

void stopConsumer() {
    if(consumer1!=NULL) {
        qDebug() << "stopConsumer";
        consumer1->stopConsume();
    }
}

如果我有一个按键调用stopConsumer.. 没关系,deleteConsumer已到达。

如果我stopConsumer在 MainWindow 析构函数内或 MainWindow 内调用closeEvent.. 永远不会到达插槽deleteConsumer

有任何想法吗?

4

2 回答 2

2

鉴于Consumer类和您的线程亲和力MainWindow不同,您对内部的调用很可能使用 a ,这意味着不会立即调用该插槽。connectinitConsumers()Qt::QueuedConnectiondeleteConsumer()

如果您想确保消费者从主窗口的析构函数中删除(或等效地,从关闭事件中删除),一种可能的解决方案是调用stopConsume()消费者,然后等到线程不再运行(参见http ://qt-project.org/doc/qt-5.1/qtcore/qthread.html#isRunning ),然后deleteConsumer()直接调用。

更新

这是我上面描述的一个例子:

consumer1->stopConsume();
consumer1->wait();
deleteConsumer();

不建议将连接类型切换为,Qt:DirectConnection因为这会导致deleteConsumer()从 的主体调用函数Consumer::run(),这可能会使您的应用程序崩溃。

于 2013-08-22T19:00:14.080 回答
0

这里的部分问题是你是从 QThread 派生的,这不是它应该被使用的方式。你可以在这里阅读为什么从 QThread 派生是错误的。

相反,您应该做的是从 QObject 派生您的类,创建一个 QThread 对象并将派生的 QObject 实例移动到该线程。

class Consumer : public QObject
{
    ...

    signals:
        void finished();

    private slots:
        void run();
}

QThread pThread = new QThread;
Consumer pObject = new Consumer;

// move the pObject to the thread
pObject->moveToThread(pThread);    

然后,您可以使用信号和插槽控制线程。

// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));

// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));

并启动线程: -

pThread->start();

使用这种方式,它还可以将多个对象移动到单个新线程,而不是为每个对象实例创建一个新线程。

于 2013-08-23T07:58:45.490 回答