Processos e threads do Qt: executando um processo e comunicação entre processos

O Qt fornece uma classe QProcess independente de plataforma para suporte ao processo. Esta seção descreve como iniciar um processo de programa externo em um aplicativo Qt, bem como vários métodos de comunicação entre processos comumente usados.

Ao projetar um aplicativo, às vezes você não deseja integrar uma função menos relevante ao programa, seja porque a função tem pouca conexão com o aplicativo atualmente projetado, seja porque a função já pode ser bem implementada com um programa existente. Nesse momento, você pode chamar um programa externo no aplicativo atual para implementar a função, que usará o processo. Os aplicativos Qt podem iniciar facilmente um aplicativo externo e o Qt também fornece uma variedade de métodos de comunicação entre processos.

1. Execute um processo

A classe QProcess do Qt pode ser usada para iniciar um programa externo e se comunicar com ele. Vamos dar uma olhada em como iniciar um processo no código Qt.

execute um processo abra o bloco de notas

Primeiro crie um aplicativo QtGui, o nome do projeto é "myProcess", e outras opções podem ser mantidas como padrão. Primeiro insira o arquivo mainwindow.h para adicionar código e adicione uma definição de objeto privado: QProcess myProcess. Em seguida, arraste um componente Push Button para a interface no modo de design e modifique seu texto de exibição para "iniciar um processo". Clique com o botão direito do mouse sobre o botão, vá até o slot correspondente ao seu sinal clicked() e altere-o da seguinte forma:

void MainWindow::on_pushButton_clicked()
{
     myProcess.start("notepad.exe");
}

Aqui usamos o objeto QProcess para executar o programa Notepad (ou seja, programa notepad.exe) no sistema Windows, porque o programa está no diretório do sistema, portanto não há necessidade de especificar seu caminho aqui. Você também pode executar qualquer outro programa, basta especificar seu caminho específico. Vimos que você pode usar start() para iniciar um programa e, às vezes, é necessário especificar parâmetros de inicialização ao iniciar um programa, o que é muito comum ao iniciar um programa a partir da linha de comando.

Execute o programa e um programa de bloco de notas aparecerá quando você clicar no botão na interface.

O QProcess também fornece um conjunto de funções que podem ser usadas fora do loop de eventos, que suspenderão o thread de chamada até que um determinado sinal seja emitido:

  • waitForStarted() bloqueia até que o processo seja iniciado;
  • waitForReadyRead() bloqueia até que haja dados legíveis no canal de leitura atual;
  • waitForBytesWritten() bloqueia até que uma carga útil de dados seja gravada no processo;
  • waitForFinished() é bloqueado até que o processo seja concluído.

Os benefícios deste artigo, a taxa para receber o pacote de materiais de aprendizado de desenvolvimento Qt, vídeo técnico, conteúdo inclui (base da linguagem C ++, introdução à programação Qt, sinal QT e mecanismo de slot, desenho de imagem de desenvolvimento de interface QT, rede QT, programação de banco de dados QT, combate de projeto QT, QSS, OpenCV, módulo rápido, perguntas de entrevista, etc.) ↓↓↓↓↓↓ Veja abaixo

Dois, comunicação entre processos

O Qt fornece uma variedade de métodos para implementar a comunicação entre processos IPC (Inter-Process Communication) em aplicativos Qt. Uma breve introdução é a seguinte:

TCP/IP

As classes fornecidas pelo módulo Qt Network de plataforma cruzada podem tornar a programação de rede mais portátil e conveniente. Ele fornece classes de alto nível (por exemplo: QNetworkAccessManager, QFtp) para comunicação usando protocolos de nível de aplicativo específicos e classes de nível inferior (por exemplo: QTcpSocket, QTcpServer, QSslSocket) para implementar protocolos.

Memoria compartilhada

A classe de memória compartilhada QSharedMemory de plataforma cruzada fornece a implementação da memória compartilhada do sistema operacional. Ele permite que vários threads e processos acessem com segurança segmentos de memória compartilhada. Além disso, o QSystemSemaphore pode ser utilizado para controlar o acesso aos recursos compartilhados pelo sistema, bem como a comunicação entre os processos.

D-Bus

O módulo D-Bus do Qt é a única biblioteca Unix disponível para implementação de IPC usando o protocolo D-Bus. Ele estende o mecanismo de sinais e slots do Qt para o nível IPC, permitindo que os sinais emitidos por um processo sejam conectados aos slots de outro processo. A documentação D-Bus do Qt tem instruções detalhadas sobre como usar os módulos D-Bus no Qt.

QProcesso

Use a classe QProcess mencionada anteriormente. A classe de plataforma cruzada QProcess pode ser usada para iniciar programas externos como processos filho e se comunicar com eles. Ele fornece uma API para monitorar e controlar o estado do processo filho. Além disso, o QProcess fornece canais de entrada/saída para subprocessos herdados do QIODevice.

gerenciamento de sessão

Na plataforma Linux/X11, o Qt oferece suporte ao gerenciamento de sessão. As sessões permitem que os eventos sejam propagados para os processos, por exemplo, quando um desligamento é detectado. Processos e aplicativos podem executar quaisquer ações necessárias, como salvar documentos abertos.

3. Exemplo de comunicação entre processos de memória compartilhada

Vamos dar uma olhada em um exemplo de uso de memória compartilhada.A função que ele implementa é: primeiro escreva uma imagem no segmento de memória compartilhada em uma caixa de diálogo e, em seguida, leia a imagem do segmento de memória compartilhada em outra caixa de diálogo.

Crie um novo aplicativo Qt Gui com o nome mylPC, o nome da classe Dialog e selecione QDialog como a classe base. Após a conclusão, entre no modo de design e coloque dois componentes Push Button e um componente Label na interface. Altere o texto de exibição de um botão para "Carregar imagem do arquivo" e sua propriedade objectName para loadFromFileButton, altere o texto de exibição do outro botão para "Exibir imagem da memória compartilhada" e sua propriedade objectName para loadFromSharedMemoryButton. Em seguida, insira o arquivo dialog.h e modifique-o da seguinte maneira:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QSharedMemory>

namespace Ui {
    class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = nullptr);
    ~Dialog();

public slots:
    //从文件中加载图片到共享内存
    void loadFromFile();

    //从共享内存中加载图片
    void loadFromMemory();

private slots:
    //从文件中加载图片按钮
    void on_loadFromFileButton_clicked();

    //从共享内存加载并显示图片按钮
    void on_loadFromSharedMemoryButton_clicked();

private:
    //将进程与共享内存段进行分离,如果失败则进行提示
    void detach();

private:
    Ui::Dialog *ui;

    QSharedMemory sharedMemory; //定义一个共享内存对象
};

#endif // DIALOG_H

Em seguida, insira o arquivo dialog.cpp e modifique-o da seguinte maneira:

#include "dialog.h"
#include "ui_dialog.h"

#include <QFileDialog>
#include <QBuffer>
#include <QDebug>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    //在使用共享内存以前,需要设置key,系统用它作为底层共享内存段的标识
    sharedMemory.setKey("QSharedMemoryExample");
}

Dialog::~Dialog()
{
    delete ui;
}

//从文件中加载图片到共享内存
void Dialog::loadFromFile()
{
    //判断该进程是否已经连接到共享内存段,连接成功返回true
    if (sharedMemory.isAttached())
        detach();

    ui->label->setText(tr("选择一个图片文件!"));
    //使用文件对话框获得打开图片路径
    QString fileName = QFileDialog::getOpenFileName(nullptr, QString(), QString(),
                                                    tr("Images (*.png *.jpg)"));

    //label标签显示图片
    QImage image;
    if (!image.load(fileName))
    {
        ui->label->setText(tr("选择的文件不是图片,请选择图片文件!"));
        return;
    }
    ui->label->setPixmap(QPixmap::fromImage(image));

    //将图片加载到共享内存
    //使用QBuffer来暂存图片,这样便可以获得图片的大小,还可以获得图片数据的指针
    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);
    QDataStream out(&buffer);
    out << image;
    int size = static_cast<int>(buffer.size());
    //使用create()函数创建指定大小的共享内存段,该函数还会自动将共享内存段连接到本进程上。
    if (!sharedMemory.create(size))
    {
        ui->label->setText(tr("无法创建共享内存段!"));
        return;
    }

    //在进行共享内存段的操作前,需要先进行加锁
    sharedMemory.lock();
    char *to = static_cast<char*>(sharedMemory.data());
    const char *from = buffer.data().data();
    //使用memcpy()函数将图片数据复制到共享内存
    memcpy(to, from, static_cast<size_t>(qMin(sharedMemory.size(), size)));
    //等操作完成后,再进行解锁。
    sharedMemory.unlock();
}

//从共享内存中加载图片
void Dialog::loadFromMemory()
{
    //使用attache()函数将进程连接到共享内存段
    if (!sharedMemory.attach())
    {
        ui->label->setText(tr("无法连接到共享内存段,\n"
                              "请先加载一张图片!"));
        return;
    }

    QBuffer buffer;
    QDataStream in(&buffer);
    QImage image;

    //使用QBuffer来读取共享内存段中的数据
    sharedMemory.lock();
    buffer.setData((char*)sharedMemory.constData(), sharedMemory.size());
    buffer.open(QBuffer::ReadOnly);
    in >> image;
    sharedMemory.unlock();

    //将进程与共享内存段进行分离,如果失败则进行提示
    sharedMemory.detach();
    ui->label->setPixmap(QPixmap::fromImage(image));
}

//将进程与共享内存段进行分离,如果失败则进行提示
void Dialog::detach()
{
    if (!sharedMemory.detach())
        ui->label->setText(tr("无法从共享内存中分离!"));
}

//从文件中加载图片按钮
void Dialog::on_loadFromFileButton_clicked()
{
    loadFromFile();
}

//从共享内存加载并显示图片按钮
void Dialog::on_loadFromSharedMemoryButton_clicked()
{
    loadFromMemory();
}

Clique no botão "Carregar imagem do arquivo" em uma instância em execução e selecione uma imagem. Clique no botão "Exibir imagem da memória compartilhada" na segunda instância em execução, então a imagem carregada na primeira instância será exibida, o efeito é o seguinte:

 

4. Análise do programa

(1)loadFromFile()

  • Aqui, primeiro use a função isAttached() para determinar se o processo foi conectado ao segmento de memória compartilhada e, em caso afirmativo, chame detach() para primeiro separar o processo do segmento de memória compartilhada.
  • Em seguida, use a classe QFileDialog para abrir um arquivo de imagem e exibi-lo no rótulo. Para carregar a imagem na memória compartilhada, o QBuffer é usado para armazenar temporariamente a imagem, de modo que o tamanho da imagem possa ser obtido e o ponteiro dos dados da imagem também possa ser obtido.
  • Posteriormente, a função create() é usada para criar um segmento de memória compartilhada de um tamanho especificado, a unidade de tamanho é o byte e essa função conectará automaticamente o segmento de memória compartilhada ao processo.
  • Ao operar o segmento de memória compartilhada, use lock() para bloqueá-lo e, em seguida, use a função memcpy() para copiar o segmento de dados correspondente ao buffer para o segmento de memória compartilhada e use unlock() para desbloqueá-lo após a conclusão da operação. Desta forma, ao mesmo tempo, apenas um processo pode operar o segmento de memória compartilhada.

(2)loadFromMemory()

  • Aqui primeiro use a função attach() para conectar o processo ao segmento de memória compartilhada.
  • Ao operar o segmento de memória compartilhada, use lock() para bloqueá-lo e, em seguida, use QBuffer para ler os dados no segmento de memória compartilhada e use unlock() para desbloqueá-lo após a conclusão da operação.
  • Como não há necessidade de usar memória compartilhada agora, chame a função detach() para separar o processo do segmento de memória compartilhada. Por fim, exiba a imagem no rótulo.

O artigo é transferido do jardim do blog (fengMisaka): Processo Qt e tópico um: executando um processo e comunicação entre processos

Os benefícios deste artigo, a taxa para receber o pacote de materiais de aprendizado de desenvolvimento Qt, vídeo técnico, conteúdo inclui (base da linguagem C ++, introdução à programação Qt, sinal QT e mecanismo de slot, desenho de imagem de desenvolvimento de interface QT, rede QT, programação de banco de dados QT, combate de projeto QT, QSS, OpenCV, módulo rápido, perguntas de entrevista, etc.) ↓↓↓↓↓↓ Veja abaixo

 

Acho que você gosta

Origin blog.csdn.net/QtCompany/article/details/131859748
Recomendado
Clasificación