如何从Qt连接到现有共享内存?

如何从Qt连接到现有共享内存?,qt,shared-memory,Qt,Shared Memory,我用C语言中的二进制代码创建了一个共享内存段,并将一些数据写入其中。现在我想从Qt读取数据。如何从Qt连接到现有共享内存?QSharedMemory实际上并不意味着与其他任何东西互操作。在Unix上,它是通过SYSV共享内存实现的,但它将特定于Qt的参数传递给ftok: ::ftok(filename.constData(), qHash(filename, proj_id)); 您可以在C代码中模拟这种行为,但我认为没有必要 不打开共享内存段,只需将文件映射到内存,并从多个进程访问它。在Qt

我用C语言中的二进制代码创建了一个共享内存段,并将一些数据写入其中。现在我想从Qt读取数据。如何从Qt连接到现有共享内存?

QSharedMemory
实际上并不意味着与其他任何东西互操作。在Unix上,它是通过SYSV共享内存实现的,但它将特定于Qt的参数传递给
ftok

::ftok(filename.constData(), qHash(filename, proj_id));
您可以在C代码中模拟这种行为,但我认为没有必要

不打开共享内存段,只需将文件映射到内存,并从多个进程访问它。在Qt上,
QFile::map
执行您需要的操作

下面的示例显示了两种技术:使用SYSV共享内存和使用内存映射文件:

// https://github.com/KubaO/stackoverflown/tree/master/questions/sharedmem-interop-39573295
#include <QtCore>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <string>
void mmap_test() {
    QTemporaryFile shmFile;
    check(shmFile.open(), "shmFile.open");
    shmFile.write({sizeof(Data), 0});
    check(true, shmFile, "shmFile.write");
    check(shmFile.flush(), shmFile, "shmFile.flush");

    // SYSV MMAP
    Handle fd{open(QFile::encodeName(shmFile.fileName()), O_RDWR)};
    check(fd.fd, "open");
    auto ptr1 = mmap(NULL, sizeof(Data), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd.fd, 0);
    check(ptr1, "mmap");
    new (ptr1) Data;

    // Qt
    auto ptr2 = shmFile.map(0, sizeof(Data));

    Data::compare(ptr1, ptr2);
}
我们需要用于C API的RAII包装器:

struct noncopyable { Q_DISABLE_COPY(noncopyable) noncopyable() {} };
struct ShmId : noncopyable {
    int id;
    ShmId(int id) : id{id} {}
    ~ShmId() { if (id != -1) shmctl(id, IPC_RMID, NULL); }
};
struct ShmPtr : noncopyable {
    void * ptr;
    ShmPtr(void * ptr) : ptr{ptr} {}
    ~ShmPtr() { if (ptr != (void*)-1) shmdt(ptr); }
};
struct Handle : noncopyable {
    int fd;
    Handle(int fd) : fd{fd} {}
    ~Handle() { if (fd != -1) close(fd); }
};
下面介绍如何在C和Qt之间互操作SYSV共享内存部分。不幸的是,除非您在C中重新实现
qHash
,否则不可能:

void ipc_shm_test() {
    QTemporaryFile shmFile;
    check(shmFile.open(), shmFile, "shmFile.open");

    // SYSV SHM
    auto nativeKey = QFile::encodeName(shmFile.fileName());
    auto key = ftok(nativeKey.constData(), qHash(nativeKey, 'Q'));
    check(key, "ftok");
    ShmId id{shmget(key, sizeof(Data), IPC_CREAT | 0600)};
    check(id.id, "shmget");
    ShmPtr ptr1{shmat(id.id, NULL, 0)};
    check(ptr1.ptr, "shmat");
    new (ptr1.ptr) Data;

    // Qt
    QSharedMemory shm;
    shm.setNativeKey(shmFile.fileName());
    check(shm.attach(QSharedMemory::ReadOnly), shm, "shm.attach");
    auto ptr2 = shm.constData();

    Data::compare(ptr1.ptr, ptr2);
}
以下是如何互操作内存映射文件:

// https://github.com/KubaO/stackoverflown/tree/master/questions/sharedmem-interop-39573295
#include <QtCore>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <string>
void mmap_test() {
    QTemporaryFile shmFile;
    check(shmFile.open(), "shmFile.open");
    shmFile.write({sizeof(Data), 0});
    check(true, shmFile, "shmFile.write");
    check(shmFile.flush(), shmFile, "shmFile.flush");

    // SYSV MMAP
    Handle fd{open(QFile::encodeName(shmFile.fileName()), O_RDWR)};
    check(fd.fd, "open");
    auto ptr1 = mmap(NULL, sizeof(Data), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd.fd, 0);
    check(ptr1, "mmap");
    new (ptr1) Data;

    // Qt
    auto ptr2 = shmFile.map(0, sizeof(Data));

    Data::compare(ptr1, ptr2);
}
最后,测试线束:

int main() {
    try {
        ipc_shm_test();
        mmap_test();
    }
    catch (const std::runtime_error & e) {
       qWarning() << e.what();
       return 1;
    }
    return 0;
}
intmain(){
试一试{
ipc_shm_测试();
mmap_测试();
}
捕获(const std::runtime_error&e){
qWarning()可能是您正在搜索的内容