How to share data between processes using QSharedMemory?
-
In my attempt bellow, when i read the struct Data on process 2
Data *dataInMemory = static_cast<Data*>(sharedMemory.data());
looks like its corrupted:and the application crash in the next line.
What i'm doing wrong?
process 1
struct Data { QMap<int, QString> map; }; Process1::Process1(QWidget* parent) : QMainWindow(parent), ui(new Ui::Process1Class()) { ui->setupUi(this); // Create an instance of QSharedMemory and attach // it to a unique key. sharedMemory.setKey("Key"); Data data; data.map[1] = "Hello"; data.map[2] = "World"; if (!sharedMemory.create(sizeof(Data))) { if (!sharedMemory.attach()) { qWarning() << "Unable to attach to shared memory: " << sharedMemory.errorString();; return; } } else { // Shared memory doesn't exist, create it and initialize the shared data. sharedMemory.lock(); Data *data = static_cast<Data*>(sharedMemory.data()); sharedMemory.unlock(); } sharedMemory.lock(); Data *dataInMemory = static_cast<Data*>(sharedMemory.data()); *dataInMemory = data; sharedMemory.unlock(); }
process 2
struct Data { QMap<int, QString> map; }; Process2::Process2(QWidget *parent) : QMainWindow(parent), ui(new Ui::Process2Class()) { ui->setupUi(this); // Create an instance of QSharedMemory and attach it // to the same key as process 1. QSharedMemory sharedMemory("Key"); if (!sharedMemory.attach()) { qWarning() << "Unable to attach to shared memory: " << sharedMemory.errorString();; return; } sharedMemory.lock(); Data *dataInMemory = static_cast<Data*>(sharedMemory.data()); QMap<int, QString> map = dataInMemory->map; sharedMemory.unlock(); }
You can not share objects snce most of them have pointers to other memory in their private implementations - only plain data, or serialized objects
-
You can not share objects snce most of them have pointers to other memory in their private implementations - only plain data, or serialized objects
@Christian-Ehrlicher how to serialize the object? qt has implementation for this task?
-
@Christian-Ehrlicher how to serialize the object? qt has implementation for this task?
@Roberrt said in How to share data between processes using QSharedMemory?:
qt has implementation for this task?
You can use QDataStream for it.
-
@Christian-Ehrlicher how to serialize the object? qt has implementation for this task?
-
I got it working now, something that i should change or take note?
process1
struct Data { QMap<int, QString> map; }; filemap1::filemap1(QWidget* parent) : QMainWindow(parent) , ui(new Ui::filemap1Class()) { ui->setupUi(this); // Create an instance of QSharedMemory and attach it to a unique key sharedMemory.setKey("MyKey"); Data data; data.map[1] = "Hello"; data.map[2] = "World"; QByteArray serializedData; QDataStream stream(&serializedData, QIODevice::WriteOnly); stream << data.map; if (!sharedMemory.create(serializedData.size())) { if (!sharedMemory.attach()) { qWarning() << "Unable to attach to shared memory: " << sharedMemory.errorString();; return; } } sharedMemory.lock(); char* sharedMemoryData = static_cast<char*>(sharedMemory.data()); std::memcpy(sharedMemoryData, serializedData.constData(), serializedData.size()); sharedMemory.unlock(); }
process2
struct Data { QMap<int, QString> map; }; filemap2::filemap2(QWidget *parent) : QMainWindow(parent) , ui(new Ui::filemap2Class()) { ui->setupUi(this); // Create an instance of QSharedMemory and attach it // to the same key as process 1 QSharedMemory sharedMemory("MyKey"); if (!sharedMemory.attach()) { qWarning() << "Unable to attach to shared memory: " << sharedMemory.errorString();; return; } sharedMemory.lock(); // Read the serialized data from shared memory char* sharedMemoryData = static_cast<char*>(sharedMemory.data()); QByteArray serializedData(sharedMemoryData, sharedMemory.size()); // Deserialize the object QDataStream stream(&serializedData, QIODevice::ReadOnly); Data data; stream >> data.map; sharedMemory.unlock(); }
How do i avoid the process getting stuck when trying to attach to a
sharedMemory
which is locked for too much time?For example, if process2 lock the
sharedMemory
and crash, when process1 try to read it, it will stuck, as it wait forever to the memory be unlocked. -
I got it working now, something that i should change or take note?
process1
struct Data { QMap<int, QString> map; }; filemap1::filemap1(QWidget* parent) : QMainWindow(parent) , ui(new Ui::filemap1Class()) { ui->setupUi(this); // Create an instance of QSharedMemory and attach it to a unique key sharedMemory.setKey("MyKey"); Data data; data.map[1] = "Hello"; data.map[2] = "World"; QByteArray serializedData; QDataStream stream(&serializedData, QIODevice::WriteOnly); stream << data.map; if (!sharedMemory.create(serializedData.size())) { if (!sharedMemory.attach()) { qWarning() << "Unable to attach to shared memory: " << sharedMemory.errorString();; return; } } sharedMemory.lock(); char* sharedMemoryData = static_cast<char*>(sharedMemory.data()); std::memcpy(sharedMemoryData, serializedData.constData(), serializedData.size()); sharedMemory.unlock(); }
process2
struct Data { QMap<int, QString> map; }; filemap2::filemap2(QWidget *parent) : QMainWindow(parent) , ui(new Ui::filemap2Class()) { ui->setupUi(this); // Create an instance of QSharedMemory and attach it // to the same key as process 1 QSharedMemory sharedMemory("MyKey"); if (!sharedMemory.attach()) { qWarning() << "Unable to attach to shared memory: " << sharedMemory.errorString();; return; } sharedMemory.lock(); // Read the serialized data from shared memory char* sharedMemoryData = static_cast<char*>(sharedMemory.data()); QByteArray serializedData(sharedMemoryData, sharedMemory.size()); // Deserialize the object QDataStream stream(&serializedData, QIODevice::ReadOnly); Data data; stream >> data.map; sharedMemory.unlock(); }
How do i avoid the process getting stuck when trying to attach to a
sharedMemory
which is locked for too much time?For example, if process2 lock the
sharedMemory
and crash, when process1 try to read it, it will stuck, as it wait forever to the memory be unlocked.@Roberrt
I think theattach()
is OK, you mean when the second process tries alock()
.
I think the answer is that Qt does not provide any kind oftryLock()
, see https://bugreports.qt.io/browse/QTBUG-4073 and https://bugreports.qt.io/browse/QTBUG-2443.
I don't know what happens of one side actually "crashes", OS-dependent behaviour as to whether it gets released.
There may be other ways to share data with IPC which don't risk thisQSharedMemory
behaviour if that is important to you. -
@Roberrt
I think theattach()
is OK, you mean when the second process tries alock()
.
I think the answer is that Qt does not provide any kind oftryLock()
, see https://bugreports.qt.io/browse/QTBUG-4073 and https://bugreports.qt.io/browse/QTBUG-2443.
I don't know what happens of one side actually "crashes", OS-dependent behaviour as to whether it gets released.
There may be other ways to share data with IPC which don't risk thisQSharedMemory
behaviour if that is important to you. -
@Roberrt
Have you read the platform description in https://doc.qt.io/qt-6/qsharedmemory.html#details ?It also says
QSharedMemory automatically destroys the shared memory segment when the last instance of QSharedMemory is detached from the segment, and no references to the segment remain.
I think if process1 exits but process 2 has attached it persists. Until all processes have released it.
-
@Roberrt
Have you read the platform description in https://doc.qt.io/qt-6/qsharedmemory.html#details ?It also says
QSharedMemory automatically destroys the shared memory segment when the last instance of QSharedMemory is detached from the segment, and no references to the segment remain.
I think if process1 exits but process 2 has attached it persists. Until all processes have released it.
-
@JonB I see, whats the best way to inform process2 that new data has been written to the QSharedMemory?
@Roberrt
You might have to have a semaphore for that. There isn't a "notification".
Before you go any further you should read- https://forum.qt.io/topic/120197/qsharedmemory-update-signal
- https://stackoverflow.com/questions/37121384/observe-changes-in-qsharedmemory
and consider your alternatives, and what you are using the shared memory for.
-
Another huge mistake people make when using shared memory is they think in terms of peer-to-peer, which is bad juju. You really have to manage shared memory as a master/slave relationship. ie, it is set-up/initialized by a controller and then some number of other processes can use it...and there is no implicit "notify of changes" mechanism. you have to poll for changes or implement some sort of cross-process signalling mechanism in addition to correct use of semaphores/mutexes.
-
Do i still need to call
.lock
into the QSharedMemory when i'm just reading it without modifying the data?@Roberrt
void *QSharedMemory::data()Remember to lock the shared memory with
lock()
before reading from or writing to the shared memoryIf you don't
lock()
for read and someone else haslock()
ed and writes, I simply don't know/maybe not defined what you see in the read. -
Do i still need to call
.lock
into the QSharedMemory when i'm just reading it without modifying the data?Read characteristics are undefined if you don't guarantee exclusive access, or at least use data types that are guaranteed to be atomic. Generally the read of a native word sized int is atomic across architectures because the CPU microcode likes to deal with a whole word at a time, and preemption wont occur in the middle of a machine code instruction.
But it is safer to lock for reads as well.