利用QSystemSemaphore和QSharedMemory实现进程间通讯

https://blog.csdn.net/liji_digital/article/details/70547082

线程间的通讯可以由QSemaphore调控,以保证各个线程对同一资源的访问不冲突

但是进程间的协调就不能利用QSemaphore,而要利用QSystemSemaphore

此外,在同一进程内的各个线程之间可以用信号-槽机制通信但是进程之间就不可以了。取而代之的是QSharedMemory

下面的两个程序test_process和ProcessClient运行在不同的进程中。前者为主进程,后者为子进程。

主进程利用QProcess::start()启动子进程。QProcess::start(QString())的作用与在命令行输入命令类似。

start的输入参数可以是一个exe文件的名字。这个exe文件在另一个进程中运行。当主进程结束,exe所在的子进程也随之结束。

先看主进程的代码:

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>
#include <qfile.h>
#include <qsystemsemaphore.h>
#include <qsharedmemory.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QProcess        m_Proc;

    QSharedMemory    m_mem;

    static QSystemSemaphore            m_lockSrc;
    static QSystemSemaphore            m_lockDst;

    void            init();
    QString            read();
    void            write();
public slots:
    void            OnClickOK(void);
    void            OnRecvProc(void);
    void            OnClickSend(void);
private:
    Ui::MainWindow *ui;
};

在头文件中,我定义了主进程向子进程写入数据的函数write(),也定义了读出子进程数据的函数read()。在实际应用中,我只用到了write()。

cpp文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <qbuffer.h>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QObject::connect(&m_Proc, SIGNAL(readyRead()), this, SLOT(OnRecvProc()));
    QObject::connect(ui->BtnOK, SIGNAL(clicked()), this, SLOT(OnClickOK()));
    QObject::connect(ui->BtnSend, SIGNAL(clicked()), this, SLOT(OnClickSend()));

    init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::init()
{
    m_mem.setKey(QString("sharedMem"));
    if (m_mem.isAttached())
    {
        m_mem.detach();
    }
    m_mem.create(1024);
}

QSystemSemaphore MainWindow::m_lockSrc(QString("lockSrc"), 1, QSystemSemaphore::Create);
QSystemSemaphore MainWindow::m_lockDst(QString("lockDst"), 0, QSystemSemaphore::Create);

void MainWindow::OnClickOK(void)
{
    QString qstrCmd = ui->lineEdit->text();
    m_Proc.start(qstrCmd);
}

void MainWindow::OnClickSend(void)
{
    write();
}

void MainWindow::OnRecvProc(void)
{
    QByteArray qba = m_Proc.readAll();
    QString qstrFeedBack(qba);

    ui->textEdit->setText(qstrFeedBack);
}

QString MainWindow::read()
{
    QBuffer buffer;
    QDataStream in(&buffer);
    QString text;  

    m_mem.lock();
    buffer.setData((char*)m_mem.constData(), m_mem.size());
    buffer.open(QBuffer::ReadOnly);
    in >> text;
    m_mem.unlock();
    qDebug() << "WriteSharedMemory:: Read:" << text;
    return text;
} 

void MainWindow::write( )
{
    QBuffer buffer;
    buffer.open( QBuffer::ReadWrite );
    QDataStream out( &buffer );
    QString text = ui->lineEdit->text();
    out << text;
    int size = buffer.size();  

    if(m_mem.size()<size)
    {
        qDebug() << "共享内存空间不够!";
        return ;
    }  

    if(m_lockSrc.acquire())
    {
        // Write into the shared memory
        m_mem.lock();
        char *to = (char*)m_mem.data();
        const char *from = buffer.data().data();
        memcpy( to, from, qMin( m_mem.size(), size ) );
        m_mem.unlock();
        m_lockDst.release();

        qDebug() << "WriteSharedMemory:: Write:" << text;
    }
}  

再看子进程。它包括两个类:Client和thrd。本来只要client一个类即可接收主线程发来的数据。但是实验发现那样会很卡顿。所以建立一个QThread的派生类--thrd。thrd负责接收主线程的数据。收到后,再利用信号槽机制传给Client,显示出来。通过开启一个线程的方式避免卡顿。
先看Client头文件:

#pragma once

#include <QWidget>
#include <qlineedit.h>
#include <QResizeEvent>
#include "thrd.h"

class Client : public QWidget
{
    Q_OBJECT

public:
    Client(QWidget *parent = 0);
    ~Client();

    thrd                        m_thrd;
    QLineEdit        *            m_pEdt;
public slots:
    void                    OnRecv(QByteArray);
protected:
    void                    resizeEvent(QResizeEvent *);
};
#include "client.h"
#include <QDebug>
#include <qbuffer.h>
#include <QMessageBox>

Client::Client(QWidget *parent)
    : QWidget(parent)
{
    QMessageBox msg;
    msg.setText("start");
    msg.exec();

    m_pEdt = new QLineEdit(this);
    QObject::connect(&m_thrd, SIGNAL(sigMsg(QByteArray)), this, SLOT(OnRecv(QByteArray)));

    m_thrd.start();
}

Client::~Client()
{
    m_thrd.terminate();
}

void Client::OnRecv(QByteArray qba)
{

    m_pEdt->setText(QString(qba));
}

void Client::resizeEvent(QResizeEvent *e)
{
    m_pEdt->setGeometry(width() / 10, height()/10, width() * 0.8, 20);
}

thrd.h

#pragma once

#include <qthread.h>
#include <qsystemsemaphore.h>
#include <qsharedmemory.h>

class thrd : public QThread
{
    Q_OBJECT
public:
    thrd(QObject * parent = 0);
    ~thrd();

    static QSystemSemaphore        m_lockSrc;
    static QSystemSemaphore        m_lockDst;
    QSharedMemory                m_mem;
    void                        read();
signals:
    void            sigMsg(QByteArray);
protected:
    void            run();
};

thrd.cpp

#include "thrd.h"
#include <qbuffer.h>
#include <qdatastream.h>

thrd::thrd(QObject * parent) : QThread(parent)
{
    m_mem.setKey(QString("sharedMem"));
}

thrd::~thrd()
{
}

QSystemSemaphore thrd::m_lockSrc(QString("lockSrc"), 1, QSystemSemaphore::Open);
QSystemSemaphore thrd::m_lockDst(QString("lockDst"), 0, QSystemSemaphore::Open);

void thrd::run()
{
    while(true)
    {
        read();
        msleep(1000);
    }
}

void thrd::read()
{
    if(m_mem.isAttached())
    {
        //qDebug() << "ReadSharedMemory:: haved attached.";
    }
    else
    {
        if(!m_mem.attach())
        {
            QSharedMemory::SharedMemoryError m = m_mem.error();
            return;  

        }
        else
        {
            //qDebug() << "ReadSharedMemory:: attach success.";
        }
    }  

    QBuffer buffer;
    QDataStream in(&buffer);
    QString text;  

    if(m_lockDst.acquire())
    {
        m_mem.lock();
        buffer.setData((char*)m_mem.constData(), m_mem.size());
        buffer.open(QBuffer::ReadOnly);
        in >> text;
        //清空缓存
        char* to = (char*)m_mem.data();
        memset(to,0,m_mem.size());
        m_mem.unlock();  

        m_lockSrc.release();  

        QByteArray qba = text.toLatin1();
        emit sigMsg(qba);
    }
}  

子进程的共享内存QSharedMemory必须使用主进程的共享内存一样的名字,并且要使用同名的信号量。但使用时,只要open即可,不需要create。

原文地址:https://www.cnblogs.com/xiangtingshen/p/11063805.html

时间: 2024-11-02 18:42:26

利用QSystemSemaphore和QSharedMemory实现进程间通讯的相关文章

.Net 利用消息在进程间通讯实现进程互操作

有时候我们会遇到需要在两个进程间通过某种方式实现互操作,方法有很多,例如你可以尝试让两个进程持续监视一个外部文件,由此文件记录各自进程的数据:还有可以使用网络端口实现进程间通讯.共享一片内存区域记录及传递各自进程的数据等:此处讲述在.net 下如何利用消息的传递及处理实现两个进程的通讯. 是的,这里所说的消息指的就是Windows的消息机制,对于 I T 菜鸟,可以这样简单理解Windows 消息机制:Windows系统可以同时运行很多很多应用程序,Windows系统要让某一个程序做一件事情,就

win32进程间通讯--共享内存

小白一枚,如有不对,请各位大神多多指教! 最近看了看win32进程间通讯.简单写了写利用共享内存实现进程间通讯 使用共享内存实现进程间通讯: 1.在WM_CREATE消息下创建文件映射内核对象 1 hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, (LPCWSTR)szName); 2.在需要进行数据共享的地方映射缓存区视图,将要写入的数据放入pbuf 1 pBuf = (c

C#进程间通讯技术-整理。

原文:C#进程间通讯技术-整理. 扩展阅读:http://www.cnblogs.com/joye-shen/archive/2012/06/16/2551864.html 一.进程间通讯的方式 1)共享内存 包括:内存映射文件,共享内存DLL,剪切板. 2)命名管道及匿名管道 3)消息通讯 4)利用代理方法.例如SOCKET,配置文件,注册表方式. 等方式. 方法一:通讯. 进程间通讯的方式有很多,常用的有共享内存(内存映射文件.共享内存DLL.剪切板等).命名管道和匿名管道.发送消息等几种方

管道实现进程间通讯 、WaitNamedPipe

一.管道实现进程间通讯 主要的理论知识 1.什么是管道以及分类 管道是两个头的东西,每一个头各连接一个进程或者同一个进程的不同代码,依照管道的类别分有两种管道,匿名的和命名的:依照管道的传输方向分也能够分成两种,单向的双向的.依据管道的特点,命名管道通经常使用在网络环境下不同计算机上执行的进程之间的通信(当然也能够用在同一台机的不同进程中)它能够是单向或双向的:而匿名管道仅仅能用在同一台计算机中,它仅仅能是单向的.匿名管道事实上是通过用给了一个指定名字的有名管道来实现的. 使用管道的优点在于:读

Paramics插件编程进程间通讯

一.进程间通讯 进程间的通讯,包括数据的交换与共享是一项实用的技术,多应用在大型系统中,一个大型的系统往往由多个程序部件组成,部件的形式是多种多样的,可以是动态链接库(DLL).Activex组件或控件,也可以是独立运行的程序.因此,在系统运行时各相关程序部件必然需要进行大量频繁的数据交换操作.动态链接库(DLL)与其主调应用程序之间的数据交换是非常容易实现的,但在两个应用程序之间,或是动态链接库与其主调应用程序之外的其他应用程序进行数据交换,就需要使用进程间通讯(interprocess co

linux进程间通讯-System V IPC 信号量

进程间通信的机制--信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信--使用信号.下面就进入信号量的讲解. 一.什么是信号量 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域.临界区域是指执行数据更新的代码需要独占式地执行.而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在

ACE框架 基于共享内存的进程间通讯

ACE框架将基于共享内存的进程间通讯功能,如其它IO组件或IPC组件一样,设计成三个组件.流操作组件ACE_MEM_Stream,连接器组件ACE_MEM_Connector,以及接收连接组件ACE_MEM_Accpter.ACE框架为基于共享内存的进程间通讯提供了两种数据传输(分发deliver)策略.一种是使用生产者-消费者队列的一对多的多用户MT策略,另一种是使用socket流的可以使用反应器响应数据接收事件的Reactor策略.不论哪一种策略都要通过socket进行TCP连接,并进行进程

Android AIDL 进行进程间通讯(IPC)

编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3.AIDL默认支持的类型包括java基本类型 (int.long.boolean等) 和 (String.List.Map.CharSequence),使用这些类型时不需要import声明.对于List和Map中的元素类型必须是AIDL支持的类型,如果使用自定义类型作为参数或者返回值,自定义类型必须实

Android进阶笔记04:Android进程间通讯之Messenger ( 区别于AIDL)

一. Android进程间通讯之Messenger 的引入 (1)引言:      平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯.它是基于消息的进程间通信,就像子线程和UI线程发送消息那样,是不是很简单,还不用去写AIDL文件,是不是有点小爽.哈哈.此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信:甚至作为一个转接处,任意两个进程都能通过服务端进行通信. (2) Messenger 与 AIDL 比较: