• Qt使用共享内存实现进程通信


    一、进程通信的介绍

    Qt提供了多种方法在Qt应用程序中实现进程间通信IPC(Inter-Process Communication)。

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

    2)共享内存
    QSharedMemory是跨平台的共享内存类,提供了访问操作系统共享内存的实现。
    它允许多个线程和进程安全地访问共享内存段。此外,QSystemSemaphore可用于控
    制系统的共享资源的访问以及进程间通信。

    3)D-Bus
    QtD-Bus模块是一个Unix库,可以使用D-Bus协议来实现进程间通信。它将Qt
    的信号和槽机制扩展到了P℃层面,允许从一个进程发射的信号关联到另一个进程的
    槽上。可以在帮助中查看DBus关键字,对应的文档中有其详细的介绍。

    4)QProcess

    上一章介绍过

    5)会话管理
    在Linux/X11平台上,Qt提供了对会话管理的支持,回话允许时间传播到进程。例如,当关机时通知进程或程序,从而可以执行一些相关的操作。

    二、共享内存的实例

    )新建Qt Widgets应用,名称为myIPC,基类选择QDialog,类名为Dialog。完成后进入设计模式,向界面中放入两个Push Button部件和一个Label部件。将一个按钮的显示文本更改为“从文件中加载图片”,将其objectName属性更改为pushButtonLoadFromFile,将另一个按钮的显示文本更改为“从共享内存显示图片”,将其objectName属性更改为pushButtonLoadFromSharedMemory。

     

    然后进入dialog.h文件,先添加头文件包含:

    1. #ifndef DIALOG_H
    2. #define DIALOG_H
    3. #include
    4. #include
    5. QT_BEGIN_NAMESPACE
    6. namespace Ui { class Dialog; }
    7. QT_END_NAMESPACE
    8. class Dialog : public QDialog
    9. {
    10. Q_OBJECT
    11. public:
    12. explicit Dialog(QWidget *parent = 0);
    13. ~Dialog();
    14. private:
    15. Ui::Dialog *ui;
    16. QSharedMemory sharedMemory;
    17. void detach();
    18. public slots:
    19. void loadFromFile();
    20. void loadFromMemory();
    21. private slots:
    22. void on_pushButtonLoadFromFile_clicked();
    23. void on_pushButtonLoadFromSharedMemory_clicked();
    24. };
    25. #endif // DIALOG_H

    cpp文件

    1. #include "dialog.h"
    2. #include "ui_dialog.h"
    3. #include
    4. #include
    5. #include
    6. Dialog::Dialog(QWidget *parent) :
    7. QDialog(parent),
    8. ui(new Ui::Dialog)
    9. {
    10. ui->setupUi(this);
    11. //在共享内存以前,需要先为其制定一个key,系统用它来作为底层共享内存段的标识。这个key可以是任意的字符串
    12. sharedMemory.setKey("QSharedMemoryExample");
    13. }
    14. Dialog::~Dialog()
    15. {
    16. delete ui;
    17. }
    18. void Dialog::loadFromFile()
    19. {
    20. //判断该进程是否已经连接到共享内存段,如果是,就将该进程与共享内存段进行分离。
    21. if(sharedMemory.isAttached())
    22. detach();
    23. ui->label->setText(tr("选择一个图片文件!"));
    24. QString fileName = QFileDialog::getOpenFileName(0,QString(),QString(),tr("Images(*.png *.jpg)"));
    25. QImage image;
    26. if(!image.load(fileName))
    27. {
    28. ui->label->setText(tr("选择的文件不是图片,请选择图片文件"));
    29. return;
    30. }
    31. ui->label->setPixmap((QPixmap::fromImage(image)));
    32. //将图片加载到共享内存
    33. QBuffer buffer;
    34. //将图片暂存到buffer中
    35. buffer.open(QBuffer::ReadWrite);
    36. //获取图片数据的指针
    37. QDataStream out(&buffer);
    38. out<
    39. //获取图片的大小
    40. int size = buffer.size();
    41. //创建指定大小的共享内存段
    42. if(!sharedMemory.create(size))
    43. {
    44. ui->label->setText(tr("无法创建共享内存段"));//
    45. return;
    46. }
    47. //在共享内存段的操作时,需要先加锁
    48. sharedMemory.lock();
    49. char * to = (char*)sharedMemory.data();
    50. const char * from = buffer.data().data();
    51. memcpy(to,from,qMin(sharedMemory.size(),size));
    52. //解锁
    53. sharedMemory.unlock();
    54. //如果将最后一个连接在共享内存段上的进程进行分离,那么系统会释放共享内存段。
    55. }
    56. void Dialog::loadFromMemory()
    57. {
    58. //将进程连接到共享内存段
    59. if(!sharedMemory.attach())
    60. {
    61. ui->label->setText(tr("无法连接到共享内存段,\n"
    62. "请先加载一张图片!"));
    63. return;
    64. }
    65. QBuffer buffer;
    66. QDataStream in(&buffer);
    67. QImage image;
    68. sharedMemory.lock();
    69. //读取内存段中的数据
    70. buffer.setData((char*)sharedMemory.constData(),sharedMemory.size());
    71. buffer.open(QBuffer::ReadOnly);
    72. in>>image;
    73. sharedMemory.unlock();
    74. sharedMemory.detach();
    75. ui->label->setPixmap(QPixmap::fromImage(image));
    76. }
    77. void Dialog::detach()
    78. {
    79. if(!sharedMemory.detach())
    80. {
    81. ui->label->setText(tr("无法从共享内存中分离"));
    82. }
    83. }
    84. void Dialog::on_pushButtonLoadFromFile_clicked()
    85. {
    86. loadFromFile();
    87. }
    88. void Dialog::on_pushButtonLoadFromSharedMemory_clicked()
    89. {
    90. loadFromMemory();
    91. }

    现在运行两次程序,在一个运行的实例上单击“从文件中加载图片”按钮,然后选择一张图片。在第二个运行的实例上单击“从共享内存显示图片”按钮,这时便会显示第一个实例中加载的图片,效果如图所示。 

     

     参考:

    Qt进程间通信_MechMaster的博客-CSDN博客_qt 进程间通信

    Qt:无法定位程序输入点于动态链接库等。_阿远苏喂喂的博客-CSDN博客_qt无法定位程序输入点于动态链接库

     

     

  • 相关阅读:
    nrf52832 GPIO输入输出设置
    leetcode难度:困难773. 滑动谜题
    Windows AD共享权限管理工具
    【BERT-多标签文本分类实战】之六——数据加载与模型代码
    JavaSE——Collection迭代器的使用及源码分析、集合删除元素、Collection常用方法
    JS高级:进程与线程
    #成为 SQL 大师#groupby 中不能有聚合函数
    Linux|centos二进制方式安装系统和网络监控神器prometheus+grafana(装逼神器它来了)
    走进API,了解数字化转型时代应用新宠
    算法提升(二) 异或法
  • 原文地址:https://blog.csdn.net/sinat_31608641/article/details/126567796