利用QSystemSemaphore和QSharedMemory实现进程间通讯
来源:互联网 发布:淘宝文件夹是哪个位置 编辑:程序博客网 时间:2024/05/21 13:56
线程间的通讯可以由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_OBJECTpublic: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); QProcess m_Proc;QSharedMemorym_mem;static QSystemSemaphorem_lockSrc;static QSystemSemaphorem_lockDst;voidinit();QStringread();voidwrite();public slots: void OnClickOK(void); void OnRecvProc(void);voidOnClickSend(void);private: Ui::MainWindow *ui;};#endif // MAINWINDOW_H
在头文件中,我定义了主进程向子进程写入数据的函数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_OBJECTpublic: Client(QWidget *parent = 0); ~Client();thrdm_thrd;QLineEdit*m_pEdt;public slots:voidOnRecv(QByteArray);protected:voidresizeEvent(QResizeEvent *);};Client.cpp:
#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_OBJECTpublic:thrd(QObject * parent = 0);~thrd();static QSystemSemaphorem_lockSrc;static QSystemSemaphorem_lockDst;QSharedMemorym_mem;voidread();signals:voidsigMsg(QByteArray);protected:voidrun();};
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);}}
运行结果:
先启动test_process.exe。在它的第一个文本框里输入ProcessClient.exe的路径,然后点击OK,启动子进程窗口。随后,你可以在父进程的同一个文本框里输入其他字符,然后点击"send",将内容发给子进程。子进程收到后,会将信息显示在自己的文本框里。在本例中,我发送的消息是12345
在本例子中,主进程给QSharedMemory命名,并且赋予它1024字节的空间。还创建了2个信号量。
子进程的共享内存QSharedMemory必须使用主进程的共享内存一样的名字,并且要使用同名的信号量。但使用时,只要open即可,不需要create。
最后解释为什么要使用两个QSystemSemaphore,而不是一个。在前面的博客<<自己对互斥和同步的理解>>一文中,我那下棋做比方解释同步和互斥。假如我只用一个semaphore,主进程写完一次数据后,可能不会等子进程读取,就会再写一次数据。这是因为系统的调度随机的,不会保证写入-读出严格交替。但是使用了2个semaphore之后,读写彼此牵制,只能一来一去,就保证了同步。
- 利用QSystemSemaphore和QSharedMemory实现进程间通讯
- 利用多线程和油槽实现进程间通讯!
- Qt共享内存实现进程间通信(QSharedMemory)
- 利用SendMessage实现C#进程间通讯
- 利用命名管道实现进程间通讯
- QSharedMemory 共享内存 进程间通信
- Qt进程间通信 之使用QSharedMemory
- 利用有名管道,实现两个独立进程间的通讯
- 利用Queue库实现python进程间通讯
- 利用自定义消息(MFC界面)实现进程间通讯
- Qt 进程通信QSharedMemory
- 管道实现进程间通讯
- 管道实现进程间通讯
- SenndMessage实现进程间通讯
- 进程间通讯实现方法
- 进程间通讯实现方法
- 管道实现进程间通讯
- 利用ServerSocket和ClientSocket实现简单通讯
- ubuntu14.04如何使用kinect2.0以及保存图片
- ZOJ
- mybatis调用存储过程 示例
- 机器学习之径向基函数网络
- C++ 著名类库
- 利用QSystemSemaphore和QSharedMemory实现进程间通讯
- 美团点评SQL优化工具SQLAdvisor开源
- 1025. 反转链表
- 字符串操作
- C++/C编程风格规范
- vue脚手架常用的规范介绍
- AutoCAD for .Net 开发环境配置
- 美团点评前端无痕埋点实践
- Python如果有的pipe安装不了,需要anaconda