【问题标题】:QSystemSemaphore::acquire() abortQSystemSemaphore::acquire() 中止
【发布时间】:2016-11-08 13:45:29
【问题描述】:

我使用 QSharedMemory 和 QSystemSemaphore 来组织多个进程之间的事件交换。 QSharedMemory 存储接收器的数量和事件数据。接收者在 QSystemSemaphore::acquire() 中等待。发送者通过 QSystemSemaphore::release([接收者数量]) 通知他们。

除了在共享内存中引入标志“real”/“fake”并随后在终止进程中生成“fake”事件之外,还有什么方法可以优雅地终止接收进程?

【问题讨论】:

  • 你的问题表述不清。您的意思是当您在线程上调用terminate 时,线程不会终止并卡在QSystemSemaphore::acquire() 中?
  • 这是一个 XY 问题:您必须让我们看到森林,而不是单个树木。你到底在做什么?很可能有一个更简单的解决方案来解决您的问题 - 无论那个问题到底是什么。请编辑问题以阐明您的系统结构,或许可以创建一个简短的测试用例。你可以easily launch multiple processes from one main.cpp!

标签: c++ linux multithreading qt semaphore


【解决方案1】:

QThread::terminate() 可以在每个平台上运行,无论线程目前正在做什么。当然,当您终止应用程序中的任何线程时,您唯一可以安全地做的另一件事就是调用abort:此时进程通常处于中断状态。 请勿在致电QThread::terminate 后执行abort()-ing 以外的任何操作。既然破坏力太大,不如放弃调用terminate,直接中止。

您的问题被表述为好像您计划在致电terminate 后继续使用该应用程序。千万不要!

唉,如果你只想让线程退出,而信号量是一个同步原语,你可以通过设置一个标志并释放信号量来轻松完成。下面是一个有点人为的例子,因为你通常不会那样使用线程池:它只是为了让代码更短。

// https://github.com/KubaO/stackoverflown/tree/master/questions/semaphore-quit-40488523
#include <QtCore>

class Worker : public QRunnable {
    static const QString m_key;
    static QAtomicInteger<bool> m_abort;
    void run() override {
        QSystemSemaphore sem{m_key};
        qDebug() << "working";
        while (true) {
            sem.acquire();
            if (m_abort.load()) {
                sem.release();
                qDebug() << "aborting";
                return;
            }
            sem.release();
        }
    }
public:
    static void acquire(int n = 1) {
        QSystemSemaphore sem{m_key};
        while (n--)
            sem.acquire();
    }
    static void release(int n = 1) {
        QSystemSemaphore{m_key}.release(n);
    }
    static void quit(int n) {
        m_abort.store(true);
        release(n);
    }
};
const QString Worker::m_key = QStringLiteral("semaphore-quit-40488523");
QAtomicInteger<bool> Worker::m_abort = false;

int main()
{
    QThreadPool pool;
    QVarLengthArray<Worker, 20> workers{20};
    for (auto & worker : workers) {
        worker.setAutoDelete(false);
        pool.start(&worker);
    }
    Worker::release(workers.size()); // get some workers churning
    QThread::sleep(5);
    Worker::acquire(workers.size()); // pause all the workers
    Worker::quit(workers.size());
    // The thread pool destructor will wait for all workers to quit.
}

【讨论】:

  • 好的,我的意思是 QThread::terminate() 之后的 QThread::wait() 在 Windows 但不是 Linux 上工作(成功完成)。而且我同意 terminate() 是不好的方法,但是有什么替代方法呢?问题不在于终止()。这是关于如何中断acquire()。
  • @groaner 同样,在QThread::terminate 之后您可以做的唯一abort()。它可以在 Windows 上运行是一个巧合。它不必工作,也不能保证工作,果然在Linux上它不工作。另一种方法是release 信号量......这是你的信号量,对吧?你一定是在做一些奇怪的事情。显示您的代码。
  • 这不是我的(进程中)信号量。它是全局(进程间)信号量(QSystemSemaphore,而不是 QSemaphore)。我用它来将事件从一个进程传递到另一个进程。如果我在一个进程中释放它,它会影响另一个进程,不是吗?
  • @groaner 它应该是。毕竟,您正在尝试唤醒进程。这个过程是否属于你 - 没关系。其他进程应该能够在没有任何新事件添加到队列的情况下被唤醒。
猜你喜欢
  • 1970-01-01
  • 2022-12-02
  • 2019-05-29
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多