[Development] Crash in QSystemSemaphore acquire/release
Calogero Mauceri
mauceri at actgate.com
Tue Mar 25 10:24:20 CET 2014
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
-------------- next part --------------
#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;
}
More information about the Development
mailing list