Qt程序与非Qt程序的共享内存/信号量通信

文章讲述了如何在Qt程序与非Qt程序之间通过QSharedMemory进行共享内存通信,强调了在设置key时需使用ftok且Qt内部使用Q作为第二个参数。同时,讨论了QSemaphore在跨平台进程同步中的问题,指出Qt程序与非Qt程序间使用信号量可能存在兼容性问题,并提出了使用C代码实现信号量操作的解决方案。
摘要由CSDN通过智能技术生成

Qt 从Qt 4.4 版本开始提供QSharedMemory类,可以实现Qt程序之间通过共享内存互通,Qt与非Qt程序通过共享内存互通.

void setKey(const QString &key)
void setNativeKey(const QString &key)

共享内存的key需要通过以上函数来设置, 对于两个Qt程序来说,使用setkey设置同一个字符串即可,而对于Qt与非Qt程序通信来说,,需要使用setNativekey. 对Qt程序需要传入一个字符串const QString &key, 而非Qt程序(比如C程序)一般需要使用ftok来创建key值,而ftok的返回值为int类型,非字符串类型,此时Qt程序的setNativekey因参数类型不匹配, 不能建立起与C程序的桥梁,进而无法实现共享内存通信.

key_t key = ftok("stringname",'A');//返回值为int类型
shmid = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0666);

在用linux 的C程序写共享内存时,基于System V的通信需要设置key,查看Qt源码, 其内部自带ftok功能, 但帮助文档并没有说明, Qt源码中对于 System V 的共享内存创建采用ftok("name","Q")来完成,其ftok 的第二个参数固定为'Q'. 此时我们需要改一下我们的C代码

key_t key = ftok("stringname",'Q');//第二个参数改为'Q'
shmid = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0666);

此时Qt程序的setNativeKey直接传入第一个参数("stringname")即可

setNativeKey("stringname");

----------------------------------------------------------------------------------------------------------------------------

对于信号量,Qt提供QSemaphore类和QSystemSemaphore类

两种的区别是:QSemaphore是轻量级信号量类, 同于线程间同步,QSystemSemaphore是重量级信号量类,可用于线程和进程间的同步.

对于Qt程序和非程序程序通信时,若使用信号量,需要使用QSystemSemaphore类 ,信号量的key需要通过setKey来设置, 和共享内存一样,Qt将ftok的第二个定死为"Q", 所以我们在创建C程序时需要和其保持一致.

void setKey(const QString &key, int initialValue = 0, AccessMode mode = Open)

在使用中发现Qt的信号量存在一定Bug, 两个Qt程序之间使用信号量完全没有问题,但是在Qt程序与非Qt程序之间使用信号量时,即使设置了相同的key,相同的semid, Qt通过acquire()函数还是获取不到资源一直阻塞.

该问题暂时无法解决,应该是Qt官方对信号量的适配性做的不好,好在Qt 支持C代码的开发,我们直接将C代码挪到Qt程序中进行编译, 不要使用Qt自带的类即可解决.

//cpp文件

int Service::sem_init(key_t key, int val)
{
    union semun un;
    semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);
    if (semid < 0)
    {
        if (errno == EEXIST)
            semid = semget(key, 1, 0666);
        else
        {
            perror("error");
            return -1;
        }
    }
    else
    {
        un.val = val;
        semctl(semid, 0, SETVAL, un);
    }
    return semid;
}

void Service::sem_op(int semid, int op)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = op;
    buf.sem_flg = 0;
    semop(semid, &buf, 1);
}



//.h文件

private:
  union semun
  {
     int val;
  };
好的,以下是一个使用QT信号量方式进行进程间通信的例程: 首先,在发送进程中,我们需要创建一个信号量对象,并对其进行加锁操作,然后将数据写入共享内存中: ```cpp #include <QSystemSemaphore> #include <QSharedMemory> #include <QBuffer> // 创建信号量对象 QSystemSemaphore semaphore("my_semaphore", 1, QSystemSemaphore::Create); // 加锁 if (!semaphore.acquire()) { qDebug() << "Cannot acquire semaphore."; return; } // 创建共享内存对象 QSharedMemory sharedMemory("my_shared_memory"); // 打开共享内存 if (!sharedMemory.create(sizeof(int))) { qDebug() << "Cannot create shared memory segment."; semaphore.release(); return; } // 将数据写入共享内存中 QBuffer buffer; QDataStream out(&buffer); out << static_cast<int>(42); const QByteArray data = buffer.data(); memcpy(sharedMemory.data(), data.constData(), qMin(sharedMemory.size(), data.size())); // 解锁 semaphore.release(); ``` 然后,在接收进程中,我们需要打开信号量共享内存,并对信号量进行加锁操作,然后从共享内存中读取数据: ```cpp #include <QSystemSemaphore> #include <QSharedMemory> #include <QBuffer> // 创建信号量对象 QSystemSemaphore semaphore("my_semaphore", 1, QSystemSemaphore::Open); // 加锁 if (!semaphore.acquire()) { qDebug() << "Cannot acquire semaphore."; return; } // 创建共享内存对象 QSharedMemory sharedMemory("my_shared_memory"); // 打开共享内存 if (!sharedMemory.attach()) { qDebug() << "Cannot attach shared memory segment."; semaphore.release(); return; } // 从共享内存中读取数据 QBuffer buffer; const char *data = static_cast<const char*>(sharedMemory.constData()); buffer.setData(data, sharedMemory.size()); int value; QDataStream in(&buffer); in >> value; qDebug() << "Received value:" << value; // 解锁 semaphore.release(); ``` 以上例程中,我们创建了一个名为“my_semaphore”的信号量对象和一个名为“my_shared_memory”的共享内存对象,然后在发送进程中对信号量进行加锁操作,写入一个整数值到共享内存中,接着在接收进程中对信号量进行加锁操作,从共享内存中读取整数值并输出,最后解锁信号量。 需要注意的是,信号量方式的进程间通信需要保证多个进程都能够访问同一个信号量对象,因此需要使用相同的信号量名称。在访问共享内存时也需要进行同步控制,以避免数据竞争问题。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值