According to the Qt docs, for UNIX (which I am assuming will include OS X):
Unix: QSharedMemory "owns" the shared memory segment. When the last thread or process that has an instance of QSharedMemory attached to a particular shared memory segment detaches from the segment by destroying its instance of QSharedMemory, the Unix kernel release the shared memory segment.
But if that last thread or process crashes without running the QSharedMemory destructor, the shared memory segment survives the crash.
If I execute your code on my Linux box you see the shared segment created:
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
...
0x5102002c 57 chrisw 600 8 1
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
...
0x5102002c 57 chrisw 600 8 1
To copy to clipboard, switch view to plain text mode
If I then exit with Control-C (because there's no other way) the program is "crashed":
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
...
0x5102002c 57 chrisw 600 8 0
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
...
0x5102002c 57 chrisw 600 8 0
To copy to clipboard, switch view to plain text mode
you see that the number of attached processes goes to zero but the shared memory persists. The OS will free memory allocated on the heap when terminated, i.e. the space occupied by the QSharedMemory controlling object, but not the resource it controlled because the destructor is not called.
A second attempt to run your code then fails:
$ ./test
"QSharedMemory::create: already exists"
No such file or directory
$ ./test
"QSharedMemory::create: already exists"
No such file or directory
To copy to clipboard, switch view to plain text mode
If I modify your code so the program terminates gracefully and ensures QSharedMemory object is destroyed:
#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
#include <QTimer>
int main(int argc, char *argv[]) {
auto memory = new QSharedMemory(&a); // <<< parented to ensure destruction
memory->setKey("foo");
if(!memory->create(8, QSharedMemory::AccessMode::ReadWrite)) {
qDebug() << memory->errorString();
qDebug() << strerror(errno);
}
QTimer::singleShot(5000,
&a,
&QCoreApplication
::quit);
// <<< quit in 5 sec return a.exec();
}
#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
#include <QTimer>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
auto memory = new QSharedMemory(&a); // <<< parented to ensure destruction
memory->setKey("foo");
if(!memory->create(8, QSharedMemory::AccessMode::ReadWrite)) {
qDebug() << memory->errorString();
qDebug() << strerror(errno);
}
QTimer::singleShot(5000, &a, &QCoreApplication::quit); // <<< quit in 5 sec
return a.exec();
}
To copy to clipboard, switch view to plain text mode
Then after deleting the persistent shared memory block with ipcrm, the program will run to a graceful completion and deallocate the shared memory object.
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32773 chrisw 600 20480 2 dest
0x00000000 32774 chrisw 600 20480 2 dest
...
chrisw@newton:/tmp/tt$ ./test &
[1] 5023
chrisw@newton:/tmp/tt$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32773 chrisw 600 20480 2 dest
0x00000000 32774 chrisw 600 20480 2 dest
0x5102002c 32778 chrisw 600 8 1
...
# program terminates after 5 seconds
chrisw@newton:/tmp/tt$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32773 chrisw 600 20480 2 dest
0x00000000 32774 chrisw 600 20480 2 dest
...
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32773 chrisw 600 20480 2 dest
0x00000000 32774 chrisw 600 20480 2 dest
...
chrisw@newton:/tmp/tt$ ./test &
[1] 5023
chrisw@newton:/tmp/tt$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32773 chrisw 600 20480 2 dest
0x00000000 32774 chrisw 600 20480 2 dest
0x5102002c 32778 chrisw 600 8 1
...
# program terminates after 5 seconds
chrisw@newton:/tmp/tt$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32773 chrisw 600 20480 2 dest
0x00000000 32774 chrisw 600 20480 2 dest
...
To copy to clipboard, switch view to plain text mode
This approach will be more resilient:
#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
#include <QTimer>
int main(int argc, char *argv[]) {
QSharedMemory memory("foo"); // scope ensures destructor is called on normal exit
// attach to shared mem foo if it exists
if(!memory.attach(QSharedMemory::AccessMode::ReadWrite)) {
// does not already exist so create it
if(!memory.create(8, QSharedMemory::AccessMode::ReadWrite)) {
qDebug() << memory.errorString();
qDebug() << strerror(errno);
}
}
QTimer::singleShot(5000,
&a,
&QCoreApplication
::quit);
// <<< quit in 5 sec return a.exec();
}
#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
#include <QTimer>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QSharedMemory memory("foo"); // scope ensures destructor is called on normal exit
// attach to shared mem foo if it exists
if(!memory.attach(QSharedMemory::AccessMode::ReadWrite)) {
// does not already exist so create it
if(!memory.create(8, QSharedMemory::AccessMode::ReadWrite)) {
qDebug() << memory.errorString();
qDebug() << strerror(errno);
}
}
QTimer::singleShot(5000, &a, &QCoreApplication::quit); // <<< quit in 5 sec
return a.exec();
}
To copy to clipboard, switch view to plain text mode
You can run ten of these simultaneously. The first to start will create, the others attach, and the last one to terminate gracefully will remove the shared memory.
Bookmarks