Qt中的进程与线程

一、进程内容:

  1. 如何在Qt应用程序中启动一个进程;
  2. 进程间通讯方法;

使用进程的原因:

(1)不希望将一个不太相关的功能集成到程序中

(2)或者是因为该功能与当前设计的应用程序联系不大

(3)或者是因为该功能已经可以使用现成的程序很好实现,可以使用进程调用外部的程序来实现该功能。

I、运行一个进程——QProcess类(继承自QIOdevice)

启动一个进程:调用start函数

void QProcess::start(const QString & program,const QStringList & arguments, OpenModemode=ReadWrite)

参数解释:program——运行的程序、arguments——命令行参数列表、OpenModemode——读写的配置

  1. 执行完start()函数后,QProcess进入Starting转态,已经运行后进入Runinig状态并发射started()信号。
  2. 当进程退出后,QProcess重新进入NotRuning状态(初始转态)并发射finished()信号。
  3. finished()信号提供了进程的退出代码和退出转态,也可以调用exitCode()来获取上一个结束的进程的退出代码,使用exitStatus()来获取退出转态。
  4. 任何时间发生错误QProcess都会发射error()信号,也可以调用error()来查看错误的类型和上次发生的错误。state()查看当前进程的转态。
  5. QProcess可以视为一个顺序I/O设备。可以调用write()向进程的标准输入进行写入,调用read()、readLine()和getChar()等从标准输出进行读取。
  6. 也可以作为QXmlReader的数据源,或者为QNetworkAcessManager产生用于上传的数据。

II、调用一个进程的思路:

  • 首构造一个进程对象(QProcess myprocess),其次再调用start()函数,向函数里面传入应用程序的路径。此时进程开始运行,可以使用它的转态查看函数或者信号函数来处理后续的事情,比如读、写操作。
  • 为了避免一直事件循环,Qt中有一组函数用于挂起调用的进程,直到相对应的信号被发射。(也就是说,调用了这些函数后,进程运行就会一直处于某一步,不会前进继续运行,一直等待能让阻塞停止的信号到达,程序就会运行到下一步,然后接着往下运行)
  1. waitForStated()阻塞,直到进程启动;用在start()之后,等待进程开始运行后,才执行后面的过程。
  2. waitForReadRead()阻塞,直到当前读通道上有可读的数据;
  3. waitForBytesWritten()阻塞,直到一个有效负载数据被写入到进程;
  4. waitForFinished()阻塞,直到进程结束; 设置等待时间,在这之前一直是进程在运行。等待时间到,则运行后面的代码。

III、Qt中进程间的通讯

>>>TCP/IP

跨平台的Qt Network模块提供了众多的类来实现网络编程。它提供了高层的类(比如QNetworkAccessManager等)来使用指定的应用程序及协议,也提供了较底层的类(例如QTcoSocket、QTcpServer和QSslSocket)来实现相关的协议。

>>>共享内存

QShareMemory是跨平台的共享内存类,提供了访问操作系统共享内存的实现。允许多个线程和进程安全的访问共享内存段。

此外,QSystem可用于控制系统的共享资源的访问以及进程间通讯。

>>>D-BUS

Qt D-BUS模块是一个Unix库,可以使用D-BUS协议来实现进程间通讯。它将Qt的信号和槽机制扩展到IPC层面,允许从一个进程发射的信号关联到另一个进程的槽。具体的内容在帮助文档中查看关键子D-BUS。

>>>QProcess

>>>会话管理

Qt提供了对会话管理的支持,会话允许时间传播到进程。例如,当关机是通知进程或者程序,从而可以执行一些相关的操作。具体内容参考Session Management关键字。

>>>QLocalSocket类本地套接字和QLocalServer类

以上的类可以看成一个模块,每个模块都有自己的通讯函数,通过不同的函数调用实现功能。可以单独使用。

进程间的通讯还要区分是自己与自己还是自己与另外的进程间的通讯,这样才能选择正确的通讯方式。

/****************************************************************************************************************************/

二、线程内容:

  1. 怎样编写一个多线程Qt应用程序;
  2. 线程同步;

Qt线程简介:Qt提供了对线程的支持,包括一组与平台无关的线程类,一个线程安全的发送事件的方式以及跨线程的信号-槽的关联。这些是的可以很轻松地开发可移植的多线程Qt应用程序,可以充分利用都处理器的机器。

优势:可以有效解决在不冻结一个应用程序用户界面的情况下执行一个耗时操作的问题。

I、使用QThread启动线程

Qt中提供了与平台无关的线程QThread。

  • 一个QThread代表了一个应用程序中可以对立独立控制的线程,它与进程中的其他线程分享数据,但是是独立运行的。
  • QThread从run()函数开始执行。默认的,run()通过调用exec()来开启时间循环,并在线程内运行一个Qt事件循环。

要创建一个线程,需要子类化QThread,并且重新实现run()函数。

class MyThread:pubilc QThread{
    protected:
        void run();
};

void MyThread::run(){
    QTcpScoket socket;
    (执行代码...)
    socket.connectToHost(hostNmae,portNumber);
    exec();
}

以上的线程子类化成功后,就可以创建一个对象,调用线程的start()函数开始执行该线程,start()默认调用run()函数。

当从run()函数返回后,线程便执行结束,就像应用程序离开main()函数一样。setStackSize()用于设置自定义堆栈的大小。

QThread的信号与状态判断函数有一下这些:

>>信号:

   >开始——>started()

   >结束——>finished()

   >终止——>terminated()

>>状态函数

   >isFinished()

   >isRunning()

wait()函数用与阻塞,一直等到该线程结束后才执行其它的程序。

<1>每个线程可以有自己的事件循环,可以通过调用exec()函数来启动时间循环,可以通过调用exit()或者quit()来停止时间循环。线程中拥有一个事件循环,使它能够关联其它线程中的信号到本线程的槽上,这使用了队列关联机制(就是在使用connect()函数进行信号和槽的关联时,将Qt::ConnectionType类型的参数指定为QtQueuedConnection)。拥有时间循环还可以使该线程能够使用需要事件循环的类,比如QTimer和QTcpSocket类等。

<2>在线程中无法使用任何界面部件类。

<3>极端情况下,可以使用terminate()函数来强制终止一个正在执行的线程。但是线程是否会立即终止,依赖于操作系统的调度策略。可以在调用terminate()函数后调用QThread::wait()来同步终止。(这种情况是任何时刻都可出现,就会导致无法进行一些清理工作,因此,一般情况下不要使用,只有在绝对必要时再使用)

<4>静态函数currentThreadId()和curruentThread()可以返回当前执行的线程的标识符。

currentThreadId()——>返回一个该线程的系统特定的ID

curruentThread()——>返回一个QThread指针

<5>平台无关的睡眠函数,sleep()秒、msleep()毫秒、usleep()微妙

/*************************创建线程的思路*************************/

一、创建QThread类的子类:就是新建一个继承子QThread的子类

class Child_Qthread : public QThread{
    Q_OBJECT
public:
    explicit  Child_Qthread(QObject* parent=0);
    ......
    (自定义的函数或者变量)
protected:
    void run();//重构函数
private:
    volatile bool stop;//定义子类私有的函数(自能被类的内部函数调用)
};

二、在需要使用这个线程的地方构造一个线程对象,调用start()函数启动线程。

另外一种创建线程的方法:

使用QObject::moveToThread()函数。

自定义一个在线程中执行的类和一个控制线程执行的类。

class Work:public QObject{
    Q_OBJECT
public:
    void doWOrk(const Qstring &parameter){
        //.....
        emit resultReady(result);
    }
signal:
    void resultReady(const Qstring &result);
};


class Controller:public QObject{
    Q_OBJECT
    QThread workerThread;
public:
    Controller(){
        Worker* worker=new Worker;
        worker->moveToThread(&workThread);//这里实现了将线程中执行的类绑定到对应的进程中。
    /*在这个构造函数里面,当这个类被构造后就会执行线程,因此,通过控制是否创建这个类的对象来
        实现是否执行线程的控制。
    */
    //........
    }
};

/********************************************************************/

猜你喜欢

转载自blog.csdn.net/pangyinglong/article/details/89703777