首页 > 编程知识 正文

qt线程池的使用,qt执行shell命令

时间:2023-05-03 14:32:40 阅读:28130 作者:947

1、QT通信机制

为了更好地实现QT的信息交换,在QT系统中建立了较为完善的通信机制。 QT的通信可以分为QT内部通信和外部通信两种。 对这两种通信机制和应用情况分析如下。

)1) QT内部的对象间通信

在图形用户界面编程中,经常需要将一个窗口部件的更改通知窗口中的其他部件,并进行相应的更改。 对于这种内部对象之间的通信,QT主要采用信号和时隙机制。 该机制是QT区别于其他GUI工具的核心机制。 大多数GUI工具通常通过定义回调函数对每个可能触发的行为执行。 该回调函数是指向函数的指针,不能保证执行函数回调时传递的函数参数类型的正确性,因此容易引起过程崩溃。

在QT中,信号和时隙的结构取代了这种繁杂且容易崩溃的对象通信机制。 信号在对象状态发生变化时发出。 插槽是类的成员函数,用于接收发送的信号并响应相应的事件。 信号和槽的连接通过connect ()函数实现。 例如,实现单击按钮以终止APP应用程序执行的代码

连接(button,signal ) clicked )、qApp,slot (quit ) )实现过程是指单击button时发出clicked信号(connect ) )的函数在这个过程中,信号的发出不关心什么样的对方接收这个信号,是否有接收的对方。

当对象的状态改变时,将发送此信号。 这时,槽也不知道有什么信号是否与自己相连,信号是否与自己相连,所以信号和槽真正实现了程序代码的封装,提高了代码的复用性。 信号和插槽的连接还提供了类型安全性,如果类型不匹配,则会将类型错误报告为警告,而不会导致系统崩溃。

)2) QT与外部设备之间的通信

QT与外部的通信主要将来自外部的消息作为事件接收处理。 外部设备主要通过插座与Qt APP应用程序相连。 下面以输入设备与QT APP应用程序之间的通信为例,说明Qt与外部通信的原理。

当QT的APP应用程序启动时,主程序通过函数调用创建并启动qwsServer服务器,并通过套接字在该服务器和输入硬件设备之间建立连接。 服务器启动后,鼠标和键盘设备将打开,打开的设备文件描述符软盘将连接到插座。 当Qt APP应用程序进入主事件循环时,事件处理程序使用Linux系统上的select函数来检测文件描述符fd的状态变化,以监听套接字。 如果文件描述符软盘的状态发生变化,则设备上有数据输入。 此时,事件处理程序会发出信号,使从设备输入的数据能够从Qt APP应用程序中及时响应。 当数据进入服务器内部时,数据作为事件排入事件队列,等待QT客户做出响应

在程序中接受处理。 完成后,将事件放入请求队列,通过服务器将事件发送到相应的硬件,完成外部输入设备与Qt APP应用程序之间的整个通信过程。

2、QProcess机制分析

QProcess类通常用于启动外部程序进行通信。 QProcess将外部进程视为规则的I/O设备,因此可以使用write (函数将进程写入标准输入,读取)、读取(getChar ) )函数实现对标准输出的读取

(1)质量通信机制

QT可以使用QProcess类实现从前端程序到外部APP应用程序的调用。 该流程的实现首先将前端运行的程序视为QT的主流程,然后通过创建主流程的子流程来调用外部APP应用程序。 因此,QProcess的通信机制被抽象为父子进程之间的通信机制。 由于QProcess是在实现父子进程之间通信的过程中使用Linux系统的无名流水线实现的,为了更清楚地说明QProcess的通信机制,这里首先介绍了无名流水线实现父子进程之间的通信机制

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

#includeintpipe(intfd[2]; 返回:成功时为0,错误时为-1

创建后,参数fd返回两个文件描述符。 软盘[0]打开进行读取,软盘[1]打开进行写入。 fork ) )函数创建子进程后,该子进程与父进程具有相同的两个文件描述符。 要实现从父进程到子进程的通信,请关闭父进程的读取端fd[0],同时关闭子进程的写入端fd[1]。 这将建立从父进程到子进程的通信连接。

由于无名管线的单向通信性,应用无名管线实现父子进程之间的双向通信至少需要应用双管线进行通信。 QProcess类的通信原理是利用多管道实现父子进程之间的通信。 但是,由于大多数外部运行的APP应用程序都是通过标准输入读取信息,并通过标准输出发送信息,所以仅靠管道是不是无法完成内外过程呢? 之间的通信。 为了解决此问题,如模块开头所述,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]复制给了标准输入,即标准输入的描述cxdyj为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类的实现机制。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。