groaner
groaner

Reputation: 540

QSystemSemaphore::acquire() abort

I use QSharedMemory and QSystemSemaphore to organize event exchange between several processes. QSharedMemory stores number of receivers and event data. Receivers are awaiting in QSystemSemaphore::acquire(). Sender notifies them via QSystemSemaphore::release([number of receivers]).

Are there any way to terminate receiver process gracefully except introducing flag "real"/"fake" in shared memory and subsequent generating "fake" event in terminating process?

Upvotes: 0

Views: 752

Answers (1)

QThread::terminate() works on every platform, no matter what the thread is doing at the moment. Of course, when you have terminated any thread in an application, the only other thing you can safely do is call abort: the process is generally in a broken state at that point. Do not do anything other than abort()-ing after you call QThread::terminate. Since it's so destructive, you might as well forego calling terminate and abort directly.

Your question is phrased as if you had plans to continue on with the application after calling terminate. You must not!

Alas, if all you want is for a thread to quit, with the semaphore being a synchronization primitive, you can do so easily by setting a flag and releasing the semaphore. The below is a somewhat contrived example, as you wouldn't normally use a thread pool that way: it's only to make the code shorter.

// 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.
}

Upvotes: 2

Related Questions