qprocess回调_QT进程间通信详细介绍及QProcess机制分析

1、QT通信机制

为了更好的实现QT的信息交互,在QT系统中创建了较为完善的通信机制。QT的通信可分为QT内部通信和外部通信两大类。对于这两类通信机制及应用场合做如以下分析:

(1)QT内部对象间通信

在图形用户界面编程中,经常需要将一个窗口部件的变化通知给窗口的其它部件使其产生相应的变化。对于这种内部对象间的通信,QT主要采用了信号和槽的机制。这种机制是QT区别于其他GUI工具的核心机制。在大部分的GUI工具中,通常为可能触发的每种行为通过定义回调函数来实现。这种回调函数是一个指向函数的指针,在进行函数回调执行时不能保证所传递的函数参数类型的正确性,因此容易造成进程的崩溃。

在QT中,信号和槽的机制取代了这种繁杂的、易崩溃的对象通信机制。信号是当对象状态改变时所发出的。槽是用来接收发射的信号并响应相应事件的类的成员函数。信号和槽的连接是通过connect()函数来实现的。例如,实现单击按钮终止应用程序运行的代码

connect(button , SIGNAL(clicked()) , qApp , SLOT(quit()) );实现过程就是一个button被单击后会激发clicked信号,通过connect()函数的连接qApp会接收到此信号并执行槽函数quit()。在此过程中,信号的发出并不关心什么样的对象来接收此信号,也不关心是否有对象来接收此信号,

只要对象状态发生改变此信号就会发出。此时槽也并不知晓有什么的信号与自己相联系和是否有信号与自己联系,这样信号和槽就真正的实现了程序代码的封装,提 高了代码的可重用性。同时,信号和槽的连接还实现了类型的安全性,如果类型不匹配,它会以警告的方式报告类型错误,而不会使系统产生崩溃。

(2)QT与外部设备间通信

QT与外部通信主要是将外部发来的消息以事件的方式进行接收处理。外部设备将主要通过socket与QT应用程序进行连接。在此,以输入设备与QT应用程序的通信为例说明QT与外部通信的原理。

在QT的应用程序开始运行时,主程序将通过函数调用来创建并启动qwsServer服务器,然后通过socket建立该服务器与输入硬件设备的连 接。服务器启动后将会打开鼠标与键盘设备,然后将打开的设备文件描述符fd连接到socket上。等到QT应用程序进入主事件循环时,事件处理程序将通过 Linux系统的select函数来检测文件描述符fd的状态变化情况以实现对socket的监听。如果文件描述符fd状态改变,说明设备有数据输入。此 时,事件处理程序将会发出信号使设备输入的数据能及时得到QT应用程序的响应。数据进入服务器内部就会以事件的形式将数据放入事件队列里,等待QT客户应

用程序接收处理。处理结束后再将事件放入请求队列里,通过服务器将事件发送到相应硬件上,完成外部输入设备与QT应用程序的整个通信过程。

2、 QProcess机制分析

QProcess类通常是被用来启动外部程序,并与它们进行通信的。QProcess是把外部进程看成是一个有序的I/O设备,因此可通过 write()函数实现对进程标准输入的写操作,通过read(),readLine()和getChar()函数实现对标准输出的读操作。

(1) QProcess通信机制

QT可以通过QProcess类实现前端程序对外部应用程序的调用。这个过程的实现首先是将前端运行的程序看成是QT的主进程,然后再通过创建主进 程的子进程来调用外部的应用程序。这样QProcess的通信机制就抽象为父子进程之间的通信机制。QProcess在实现父子进程间的通信过程中是运用 Linux系统的无名管道来实现的,因此为了能更加清楚的说明QProcess的通信机制,在此首先介绍关于无名管道实现父子进程间的通信机制。

无名管道是一种只能够在同族父子之间通信,并且在通信过程中,只能从固定的一端写,从另一端读的单向的通信方式。该无名管道是通过调用pipe()函数而创建的。创建代码如下:

#include  int pipe(int fd[2]) ;  返回:若成功则为0,若出错则为-1

创建后经参数fd返回两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。经过fork()函数创建其子进程后,子进程将拥有与父进程相 同的两个文件描述符。如果想要实现父进程向子进程的通信则关闭父进程的读端fd[0],同时关闭子进程的写端fd[1]。这样就建立了从父进程到子进程的 通信连接。

由于无名管道的单向通信性,所以如果要应用无名管道实现父子进程之间的双向通信则至少需要应用双管道进行通信。QProcess类的通信原理就是利 用多管道实现了父子进程之间的通信。然而对于外部运行的应用程序大都是通过标准输入而读得信息,通过标准输出而发送出信息,因此只通过建立管道并不能完成 内外进程?之间的通信。要解决此问题,就如该模块开始时所说,QProcess是把外部进程看成是一个I/O设备,然后通过对I/O设备的读写来完成内外 进程的通信。

在QProcess中父子进程之间是通过管道连接的,要实现子进程能从标准输入中读得父进程对管道的写操作,同时父进程能从管道中读得子进程对标准 输出或标准容错的写操作,就要在子进程中将管道的读端描述符复制给标准输入端,将另外管道的写端描述符复制给标准输出端和标准容错端,即实现管道端口地址 的重定向。这样子进程对标准输入、标准输出及标准容错的操作就反应到了管道中。

QProcess在正常渠道模式下具体实现共用了五个无名管道进行通信。五个管道的描述符分别用 childpipe[2],stdinChannelpipe[2],stdoutChannelpipe[2],stderrChannelpipe[2] 和deathpipe[2]五个数组来保存。deathpipe指代的管道会用在消亡的子进程与父进程之间。当子进程准备撤销时会发送一个表示该子进程消 亡的字符给父进程来等待父进程进行处理。stdinChannelpipe,stdoutChannelpipe和stderrChannelpipe所

指代的管道分别与标准输入,标准输出和标准容错进行绑定,实现了与外部程序的通信。childpipe指代的管道主要是为父子进程之间的通信而建立的。

如果在管道中有新数据写入,就会通知相应进程去读。另外图2是QProcess在正常渠道模式下的通信原理图,如果是在融合渠道模式下,将没有容错 管道,此时原理图中将没有第一个管道,也就不会有管道描述符。同时,标准容错端和标准输出端将共同挂接到子进程的stdoutChannelpipe的写 端,来实现内外进程的通信。

(2) QProcess应用方式

由于QProcess类实现了对底层通信方式较为完善的封装,因此利用QProcess类将更为方便的实现对外部应用程序的调用。在此,通过在QT界面中调用外部mplayer的例子来简单说明QProcess的应用方式。

const QString mplayerPath("/mnt/yaffs/mplayer");

const QString musicFile("/mnt/yaffs/music/sound.mp3");

QProcess* mplayerProcess=new QProcess();

QStringList args;

args<

args<

args <

args <

args<

mplayerProcess->setProcessChannelMode(QProcess::MergedChannels);

mplayerProcess->start(mplayerPath,args);

第一行指明了所要调用的外部应用程序mplayer的位置。

第二行指明了所要播放的声音文件及目录路径。

第三行创建一个指向类QProcess的指针。

第四到第九行指定mplayer参数,具体参数可以查看maplayer参数介绍。

-slave参数表示打开slave模式. 这用来将MPlayer作为其它程序的后端. MPlayer将从他的标准输入读取简单命令行, 而不再截获键盘事件.SLAVE模式协议部分将解释其语法。

-quiet显示较少的输出和状态信息。

-wid可以为mplayer指定输出窗口。

-af volume=10选择输出音量级别为10.这个选项是不可重入的, 所以对每个音频流只能使用一次。

第十行为设置进程渠道的模式为融合模 式,即将标准输出和标准容错绑定到同一个管道的写端。

第十一行为启动外部应用程序mplayer。内核中管道及通信环境的建立都是在此步中完成的。

mplayer在slave模式下运行会自动从标准输入中读取信息并执行。由QProcess的通信原理可知,管道的读端描述符

stdinChannelpipe[0]复制给了标准输入,即标准输入的描述符也为stdinChannelpipe[0],因此按照标准输入的描述符去 读信息就是到stdinChannelpipe所对应的管道中读取信息。所以如果想在QT的主进程中发送命令使mplayer退出,只需在主程序中向 stdinChannelpipe[1]端写入命令quit就可以,执行语句为myProcess->write(”quit ”);(此处的 write()函数为QProcess类的成员函数,具体实现就是向stdinChannelpipe[1]端写入信息)

(3)QProcess的发展及分析

QProcess类伴随着QT/Embedded的发展逐渐趋于完善。在QTE2及其更前版本中还没有QProcess类,如果想实现与外部应用程 序的通信,必须要自己实现对管道或socket的建立与重定向。到了QTE3版本,就实现了对QProcess类的封装。在QTE3的版本 中,QProcess类的实现是通过应用socket来建立主进程与外部应用程序之间通信的。通信原理与图3所示基本相同,只是将图中的管道描述符改为是 socket的描述符即可。QT主程序在建立成对socket描述符时需要调用Linux系统函数socketpair()。在生成的成对socket描

述符之间可以实现父子进程之间的双向通信,即无论是socket的0套接口还是1套接口都可进行读写。

但为了避免出现通信过程中父子进程对同一个socket的争夺,例如,在子进程还未将父进程发送的信息全部读出时,子进程又要求将自己产生的数据返 回给父进程。如果父子进程双向通信只用一个socket来完成,就会出现父子进程发送的信息混乱情况。因此,对于QProcess的实现仍然必须通过多个 socket来共同完成。

由上面的描述可知,尽管socket有双向通信功能,但在实现QProcess过程中只是利用socket实现了单向通信功能。因此既浪费了对资源 的利用又增加了系统的开销。为了解决此问题,QTE4版本将QProcess的通信连接方式由socket改为了只能实现单向通信的无名管道来实现。通信 原理就是以上3.1 QProcess通信机制中所描述的。

3、其它通信方式

除了上面介绍的无名管道和socket通信方式外,一般操作系统中常用的进程间通信机制也都可以用于QT系统内部不同进程之间的通信,如消息队列、共享内存、信号量、有名管道等机制。其中信号量机制在QT中已经重新进行了封装;有些机制则可以直接通过操作系统的系统调用来实现。另外,如果我们只是想通过管道或socket来实现较简单的外部通信,也可以重新创建管道或socket来实现自己要求的功能。例如,还是在QT主程序中调用外部mplayer。如果我们只是想在QT主程序中控制mplayer,而不要求得到mplayer输出的信息。则可以按照以下方式来实现:

const char* mplayerPath = "/mnt/yaffs/mplayer";

const char* musicFile = "/mnt/yaffs/music/sound.mp3";

const char* arg[5];

arg[0] = mplayerPath;

arg[1] = "-slave";

arg[2] = "-quiet";

arg[3] = musicFile;

arg[4] = NULL;

int fd[2],pid;

if(pipe(fd)<0)

printf("creating pipe is error ");

else while((pid=fork())<0);

if(pid==0)

{

::close(fd[1]);

::dup2(fd[0],STDIN_FILENO);

execvp(arg[0],(const* char*)arg);

}

else

{

::close(fd[0]);

}

第1到8行与前面QProcess类实现调用mplayer一样,是用来指明mplayer运行时参数的。第10行是创建一个管道。第12行是创建一个子进程。15,20行是关闭父子进程中没用的管道描述符。此时可结合图2.1和图2.2来理解从父进程到子进程通信环境的建立。第16行是把子进程的读端与标准输入绑定,以便mplayer能够接收到父进程发出的命令。17行就是从子进程中调用外部mplayer的实现。此时,程序执行后,mplayer就可以运行起来。如果想在QT主程序中通过发送命令使mplayer退出,就在管道的写端写入命令"quit"就可以。实现语句为write(fd[1],

"quit",strlen("quit"));

该例子说明了QT通信方式运用的灵活性,可以根据实际情况进行应用。同时该例子的实现方式正是利用了QProcess类实现的机制,因此可以结合这个例子更加深刻的理解QProcess类的实现机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/244216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1 数列分块入门_线性代数入门——利用分块矩阵简化矩阵乘法运算

系列简介&#xff1a;这个系列文章讲解线性代数的基础内容&#xff0c;注重学习方法的培养。线性代数课程的一个重要特点(也是难点)是概念众多&#xff0c;而且各概念间有着千丝万缕的联系&#xff0c;对于初学者不易理解的问题我们会不惜笔墨加以解释。在内容上&#xff0c;以…

junit可执行但控制层无法执行_Junit测试时ContextLoader.getCurrentWebApplicationContext()返回空值...

Junit测试时&#xff0c;test类调用manage类&#xff0c;manage类调用dao类dao类的代码中有如下语句:ContextLoader.getCurrentWebApplicationContext()执行这条语句时返回空值,程序代码如下:下面给出junit测试时的错误语句下面给出Junit运行时控制台输出的语句:九月 26, 2014 …

h5首页加载慢_H5网站制作注意了

H5自适应网站越来越受到企业的追捧&#xff0c;不同于原来的建站模式&#xff0c;H5网站可以很好是调整来达到PC端和移动端的良好展示效果&#xff0c;获得更友好用户体验。H5网站作为网站优化人员&#xff0c;小编第一个想到的并不是H5带来的炫酷效果&#xff0c;认识它解决了…

阿联酋esma认证_阿联酋无人驾驶汽车预计2021年上路

本报讯 迪拜消息-----据《海湾时报》11月26日报道&#xff0c;阿联酋标准化与计量局(ESMA&#xff1b;EmiratesAuthorityfor StandardisationandMetrology)局长AbdullaAlMaeeni表示&#xff0c;阿联酋准备成为全球第一个对无人驾驶汽车制订相关法规的国家&#xff0c;无人驾驶…

PyQt5 电报实时聊天软件 BB-Telegram Pt.0

使用PyQt5实现实时聊天软件 BB-Telegram 是在我BB实时聊天软件上修改的实时显示电报 源代码见下https://github.com/JiayouQin/Python-projects/tree/master/11%20PyQt5%20BB%20Telegram/CN 鉴于PyQt5实现功能篇幅较长&#xff0c;Pt.0不介绍实现过程。 程序主要功能&#…

base cap 分布式_高并发架构系列:详解分布式一致性ACID、CAP、BASE,以及区别

在面试环节&#xff0c;经常会问CAP、BASE等相关的分布式理论&#xff0c;其实这些名词主要还是来自于分布式的一致性&#xff0c;今天主要介绍分布式一致性&#xff1a;强一致性、最终一致性、ACID、CAP等理论。分布式一致性的背景随着分布式事务的出现&#xff0c;传统的单机…

读取剪贴板英语转换为国际莫斯码

Python全代码如下 执行代码之后会自动检测按键&#xff0c;按下CtrlZ之后程序读取剪贴板然后转换为莫斯码再次写入剪贴板 使用第三方模块&#xff1a; pynput win32clipboard 文章尾部附带国际莫斯码表 示例&#xff1a; Caesar openly defied the Senates authority by cros…

asp python 定时任务_Python定时任务轻量解决方案——Schedule

写后端的同学们可能都知道&#xff0c;工作中可能需要周期性执行一些任务&#xff0c;俗称定时任务。Linux环境下&#xff0c;可以借助于系统自带的crontab完成定时任务。但是很多时候&#xff0c;开发的同学们可能并没有权限去操作crontab&#xff0c;所以就催生了一些不太好的…

Pygame简单深度优先算法生成迷宫

学习路径计算之前需要一个场景&#xff0c;网上查了下迷宫生成方法花了点时间写了个简单的迷宫生成器 基本原理十分简单&#xff1a; 使用2维矩阵表示迷宫&#xff0c;每一个节点有四面墙&#xff0c;使用深度搜索&#xff0c;随机顺序向四个方向移动,&#xff0c;如果遇到已到…

wait放弃对象锁_终于搞懂了sleep/wait/notify/notifyAll,真的是不容易

sleep/wait/notify/notifyAll分别有什么作用&#xff1f;它们的区别是什么&#xff1f;wait时为什么要放在循环里而不能直接用if&#xff1f;简介首先对几个相关的方法做个简单解释&#xff0c;Object中有几个用于线程同步的方法&#xff1a;wait、notify、notifyAll。public c…

Pygame 使用Djkstra广度搜索寻找迷宫(相对)最短路径

基于之前写的迷宫生成器实现了Djkstra算法搜索路径。 https://blog.csdn.net/ChillingKangaroo/article/details/122800431 Djkstra基于广度优先算法&#xff0c;与简单搜索不同的是Djkstra在访问每一个节点的时候会计算到该节点的最短路径以及上一个节点&#xff0c;如果有新…

python打乱list_超实用!每 30 秒学会一个 Python 小技巧,GitHub 标星 5300!

公众号关注 “GitHubDaily”设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01;很多学习 Python 的朋友在项目实战中会遇到不少功能实现上的问题&#xff0c;有些问题并不是很难的问题&#xff0c;或者已经有了很好的方法来解决。当然&#xff0c;孰能生巧&#xff0c;当…

(开源)Flask+Vue+Bootstrap3 人力资源用Web数据库

闲着没事写了一个轻量级web数据库&#xff0c;在网页端访问并操作SQL&#xff0c;可以进行Excel(xlsx)数据导入\导出&#xff0c;包含用户注册\登录\授权功能&#xff0c;密码有hash&#xff0c;授权目前比较简陋&#xff1a;后端使用了一个列表储存授权用户 已授权用户&#…

access找不到输入表或者dual_在Access窗体中显示指定路径的图片

↑↑↑点击上方图片&#xff0c;了解详情在Access中&#xff0c;如果把图形对象以OLE格式的字段保存&#xff0c;那么在窗体中可以直接显示出图片来。但是这样做有以下不足&#xff1a;一、需要将图片逐一插入到表中&#xff0c;工作量太大。二、使数据库文件变得庞大。三、相同…

LeetCode 168. Excel列表名称详解

刷到了这一道简单难度题 https://leetcode-cn.com/problems/excel-sheet-column-title/https://leetcode-cn.com/problems/excel-sheet-column-title/ 粗看就是一道进制转换题不过容易掉坑里。 首先略讲一下进制转换&#xff0c; 以701为例&#xff0c;该数字可以转换为以下…

可视化管理_RFID技术实施智能仓储管理可视化

仓储物流管理在各个行业都非常重要&#xff0c;RFID技术助力仓储物流信息管理提高供应链管理的透明度和库存周转率&#xff0c;这样有效减少缺货损失&#xff0c;提高企业内的仓储物流效率。仓库管理过程中&#xff0c;存在区域划分笼统&#xff0c;不容易辨识&#xff0c;货物…

(包含重力矢量)Pygame粒子模拟

半成品&#xff0c;目前速度不能修改&#xff0c;另外某些状况下路径会比较奇怪&#xff0c;因为没有速度计算&#xff0c;包含了重力矢量&#xff0c;可以修改重力方向 import pygame as pg import math import time import random import mathclass Particle(): #Tile is for…

小米蓝牙左右互联_解决不同品牌智能家居的兼容问题,小米米家智能多模网关发布...

如今智能家居种类可谓异常丰富&#xff0c;许多智能家居确实能让日常生活变得更加便捷。但是&#xff0c;相信许多智能家居爱好者都有一个烦恼&#xff0c;不同的品牌智能家居几乎不能实现交互&#xff0c;比如现在正使用Zigbee协议的智能家居&#xff0c;但新购置的智能家居却…

Pygame列表(链表)简单实现贪吃蛇

主要算法&#xff1a; 创建一个二维矩阵映射到屏幕上的像素&#xff0c;逻辑在该矩阵中实现 移动通过4个矢量完成&#xff0c;矢量储存在列表中按照 上右下左 的顺序排列&#xff08;顺时针90度&#xff09;&#xff0c; 当前矢量以0-3的数字表达&#xff0c;这样进行加二除…

Pygame 整活五子棋

很早之前写了一个类似的五子棋&#xff0c;没有做到pygame里面&#xff0c;闲着没事给整过来了&#xff0c;主要就是加了一个鼠标映射坐标。 表情被锤会变脸。 设置的0积分不知道能不能下载 https://download.csdn.net/download/ChillingKangaroo/82109145 代码不多&#x…