利用QSystemSemaphore和QSharedMemory实现进程间通讯
Posted xiangtingshen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用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。
以上是关于利用QSystemSemaphore和QSharedMemory实现进程间通讯的主要内容,如果未能解决你的问题,请参考以下文章