Hi,

I've been digging for days in a very weird problem I found testing a producer/consumer implementation using QSystemSemaphore for IPC communication.

I used QSystemSemaphore to synchronize the producer and the consumer processes. The implementation is working like a charm on Windows/Linux while it is crashing on Mac OS when an acquire on the semaphore is performed.

Looking into the Qt implementation, I found out that on unix, the system semaphore acquire/release is implemented calling semop with SEM_UNDO flag. If the semop fails a new semaphore is created and a new semop is performed on it and so on till there is a successful semop. The crash is due to an infinite recursive loop due to a permanent failure in modifySemaphore() call. This is happening because on Mac OS there is a limit set to 10 for the maximum number of SEM_UNDO structures a process can have initialized to a value different than 0 (just launch from command line 'sysctl kern.sysv.semume' to know that value). When more than 10 semaphores have the SEM_UNDO initialized, then the modifySemaphore() will always fail causing the crash.

Attached is a simple example demonstrating the issue. A pool of producers threads are created. After acquire/release have been performed on more than 10 semaphores I get the crash on the mac.

Why the modifySemaphore, in the unix implementation, should create a new semaphore if the semop is failing? Furthermore, I think calling the semop with the SEM_UNDO flag is basically wrong in the producer/consumer case, where a resource is always acquired by a process and released by another one (the SEM_UNDO counter for each process would be wrong, causing a bad semaphore value reset on process closure). The Qt API should provide a way to acquire/release the semaphore without the SEM_UNDO flag.

I just made a bugreport https://bugreports.qt-project.org/browse/QTBUG-37766

Thanks,
    Calogero

--
Calogero Mauceri
Software Engineer

Applied Coherent Technology Corporation (ACT)
www.actgate.com

#include <QCoreapplication>
#include <QDebug>
#include <QSystemSemaphore>
#include <QThread>


class Producer : public QThread
{
public:
    Producer(int idx)
        {
                threadIdx = idx;

        QString freeBytesSemKey = QString("FB%1").arg(idx);
        QString usedBytesSemKey = QString("UB%1").arg(idx);

        // qDebug () << "key " << idx << freeBytesSemKey << usedBytesSemKey;

                // system semaphores shared with consumer
        freeBytes = new QSystemSemaphore(freeBytesSemKey, 1, 
QSystemSemaphore::Create);
        usedBytes = new QSystemSemaphore(usedBytesSemKey, 0, 
QSystemSemaphore::Create);
        }
        ~Producer()
        {
                delete freeBytes;
                delete usedBytes;
        }
        void run()
        {
        int i = 0;
                while (1)
                {
                        freeBytes->acquire();
                        // ...
                        qDebug() << "thread" << threadIdx << " block " <<  ++i 
<< " data produced ...";
                        usedBytes->release();

            // just to emulate other stuff delay
            sleep(10);
                }
        }

private:
        int threadIdx;
        QSystemSemaphore *freeBytes;
        QSystemSemaphore *usedBytes;
};

int main(int argc, char ** argv)
{
        QCoreApplication app(argc, argv);
    const int nThreads = 10;
        QThread *producersPool[nThreads];

    // launch a pool of producers
        for (int i = 0; i < nThreads; i++)
        {
                producersPool[i] = new Producer(i);
        }
    for (int i = 0; i < nThreads; i++)
    {
        qDebug() << "Launching producer thread " << i;
        producersPool[i]->start();
    }

        // wait
        producersPool[0]->wait();

        return 0;
}
_______________________________________________
Development mailing list
Development@qt-project.org
http://lists.qt-project.org/mailman/listinfo/development

Reply via email to