利用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。

 

posted @ 2019-06-21 11:57  狂奔~  阅读(2070)  评论(0编辑  收藏  举报