0

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?

groaner
  • 540
  • 4
  • 12
  • you quesiton is unclear formulated. You mean when you call `terminate` on the thread the thread does not teminate and is stuck in `QSystemSemaphore::acquire()` ? – Hayt Nov 08 '16 at 13:56
  • This is an XY problem: you must let us see the forest, not the individual trees. What exactly are you doing? Most likely there's a much simpler solution to your problem - whatever that problem really is. Please edit the question to clarify the structure of your system, perhaps creating a short test case. You can [easily launch multiple processes from one `main.cpp`!](http://stackoverflow.com/a/18602568/1329652). – Kuba hasn't forgotten Monica Nov 08 '16 at 15:11

1 Answers1

2

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.
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • OK, I mean that QThread::wait() after QThread::terminate() works (successfully completed) on Windows but not Linux. And I agree that terminate() is bad way, but what are the alternatives? The question is not about terminate(). It is about how to interrupt acquire(). – groaner Nov 08 '16 at 14:20
  • @groaner Again, the **only** thing you can do after `QThread::terminate` is `abort()`. That it works on Windows is a coincidence. It doesn't have to work, and it's not guaranteed to work, and sure enough on Linux it doesn't work. The alternative is to `release` the semaphore... it's your semaphore, right? You must be doing something weird to it. Show your code. – Kuba hasn't forgotten Monica Nov 08 '16 at 14:36
  • It is not my (inprocess) semaphore. It is global (interprocess) semaphore (QSystemSemaphore, not QSemaphore). I use it to deliver events from one processes to another ones. If I'l release it in one process it can affect another ones, can't it? – groaner Nov 08 '16 at 15:07
  • @groaner It's supposed to. After all, you're attempting to wake processes up. Whether the process is yours or not - doesn't matter. The other processes should be able to survive being woken up without any new events added to the queue. – Kuba hasn't forgotten Monica Nov 08 '16 at 15:10