欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Qt 中的 QThread:使用 QSemaphore 实现多线程数据同步

最编程 2024-05-22 22:46:38
...

20210127:在生产者、消费者的方法中添加线程挂起方法QThread::usleep(10),使ui不卡。

20210128:在添加Track类(保存生产者Producer生成的每组数据),在ui界面中使用model-view同步显示生产者生成的数据,model-view不会对主线程造成卡顿。对消费者同样创建view,还没有进行model绑定。

避免引起主线程的阻塞,Qt在子线程中处理大数据,当多个子线程需要处理同一块数据时,需要使用数据同步,避免出现调用错乱情况,在这里我们在两个子线程使用QSemaphore作为标志位,对数组进行标识,生产者线程将生成的资源存入数组,消费者数组消耗数组内的资源,当有一方的速度过快导致数组资源耗尽时,该子线程被阻塞,直到有资源时子线程继续。代码如下:

在全局变量中声明数组、数组大小、资源总量:

constant_variable.h

 1 #ifndef CONSTANT_VARIABLE_H
 2 #define CONSTANT_VARIABLE_H
 3 
 4 // 所有变量在h文件中均是声明,定义在cpp文件中
 5 
 6 /*****************************************************************************************
 7   @copyright 2013-2020
 8   @author    qiaowei
 9   @contact   weiweiqiao@126.com
10   @version   1.0
11   @date      2021-01-24
12   @brief     h文件声明extern变量,cpp文件定义变量
13 ******************************************************************************************/
14 
15 #include <QSemaphore>
16 
17 /***************************************************************************
18   @copyright 2013-2020
19   @author    qiaowei
20   @contact   weiweiqiao@126.com
21   @version   1.0
22   @date      2021-01-24
23   @brief     设置循环保存数据的数组大小,相当于设置“缓存”大小
24 ***************************************************************************/
25 extern const int BUFFER_SIZE;
26 
27 /***************************************************************************
28   @copyright 2013-2020
29   @author    qiaowei
30   @contact   weiweiqiao@126.com
31   @date      2021-01-24
32   @brief     要读取的总资源数量,数据量大,无法一次读取完,需要长时间,分批读取
33 ***************************************************************************/
34 extern const int DATA_SIZE;
35 
36 /***************************************************************************
37   @copyright 2013-2020
38   @author    qiaowei
39   @contact   weiweiqiao@126.com
40   @date      2021-01-24
41   @brief     循环使用,保存数据资源的数组
42 ***************************************************************************/
43 extern char BUFFER[];
44 
45 /***************************************************************************
46   @copyright 2013-2020
47   @author    qiaowei
48   @contact   weiweiqiao@126.com
49   @date      2021-01-24
50   @brief     标识Producer可以保存资源的空余位置的数量,保存在数组中的数据量,因为初
51              始状态数组中没有任何数据,数组有DATA_SIZE个资源可用
52 ***************************************************************************/
53 extern QSemaphore PRODUCER_SPACE;
54 
55 /***************************************************************************
56   @copyright 2013-2020
57   @author    qiaowei
58   @contact   weiweiqiao@126.com
59   @date      2021-01-24
60   @brief     标识Consumer可以使用的已保存资源的数量,因为初始时没有数据可供Consumer
61              使用,初始资源有0个
62 ***************************************************************************/
63 extern QSemaphore CONSUMER_SPACE;
64 
65 #endif // CONSTANT_VARIABLE_H

 constant_variable.cpp

 1 #include "constant_variable.h"
 2 
 3 const int BUFFER_SIZE(4096);
 4 
 5 const int DATA_SIZE(100000);
 6 
 7 // 定义数组大小为BUFFER_SIZE
 8 char BUFFER[BUFFER_SIZE];
 9 
10 // 初始时可用资源位BUFFER_SIZE
11 QSemaphore PRODUCER_SPACE(BUFFER_SIZE);
12 
13 QSemaphore CONSUMER_SPACE(0);

创建窗体:

Producer按钮生成资源,保存到数组中,在左侧文本框中显示Producer所在的线程及生成的资源。Consumer按钮消耗数组中的资源,在左侧文本框中显示Consumer所在的线程及消耗的资源。这两个按钮是单独运行。Both_start_PushButton按钮同时启动两个子线程,一个生产资源,一个消耗资源,生产和消耗的都在左边的文本框中显示。

窗口代码如下:

producer_consumer_dialog.ui 代码:

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <ui version="4.0">
  3  <class>Producer_consumer_dialog</class>
  4  <widget class="QDialog" name="Producer_consumer_dialog">
  5   <property name="geometry">
  6    <rect>
  7     <x>0</x>
  8     <y>0</y>
  9     <width>722</width>
 10     <height>451</height>
 11    </rect>
 12   </property>
 13   <property name="windowTitle">
 14    <string>Dialog</string>
 15   </property>
 16   <layout class="QVBoxLayout" name="verticalLayout_3">
 17    <item>
 18     <layout class="QHBoxLayout" name="horizontalLayout">
 19      <item>
 20       <widget class="QPlainTextEdit" name="producer_plainTextEdit"/>
 21      </item>
 22      <item>
 23       <layout class="QVBoxLayout" name="verticalLayout">
 24        <item>
 25         <widget class="QPushButton" name="producer_pushButton">
 26          <property name="text">
 27           <string>Producer</string>
 28          </property>
 29         </widget>
 30        </item>
 31        <item>
 32         <spacer name="verticalSpacer">
 33          <property name="orientation">
 34           <enum>Qt::Vertical</enum>
 35          </property>
 36          <property name="sizeType">
 37           <enum>QSizePolicy::Expanding</enum>
 38          </property>
 39          <property name="sizeHint" stdset="0">
 40           <size>
 41            <width>20</width>
 42            <height>40</height>
 43           </size>
 44          </property>
 45         </spacer>
 46        </item>
 47       </layout>
 48      </item>
 49      <item>
 50       <widget class="QTableView" name="producer_tableView"/>
 51      </item>
 52     </layout>
 53    </item>
 54    <item>
 55     <layout class="QHBoxLayout" name="horizontalLayout_2">
 56      <item>
 57       <widget class="QPlainTextEdit" name="consumer_plainTextEdit"/>
 58      </item>
 59      <item>
 60       <layout class="QVBoxLayout" name="verticalLayout_2">
 61        <item>
 62         <widget class="QPushButton" name="consumer_pushButton">
 63          <property name="text">
 64           <string>Consumer</string>
 65          </property>
 66         </widget>
 67        </item>
 68        <item>
 69         <spacer name="verticalSpacer_2">
 70          <property name="orientation">
 71           <enum>Qt::Vertical</enum>
 72          </property>
 73          <property name="sizeHint" stdset="0">
 74           <size>
 75            <width>20</width>
 76            <height>40</height>
 77           </size>
 78          </property>
 79         </spacer>
 80        </item>
 81       </layout>
 82      </item>
 83      <item>
 84       <widget class="QTableView" name="consumer_tableView"/>
 85      </item>
 86     </layout>
 87    </item>
 88    <item>
 89     <layout class="QHBoxLayout" name="horizontalLayout_3">
 90      <item>
 91       <spacer name="horizontalSpacer">
 92        <property name="orientation">
 93         <enum>Qt::Horizontal</enum>
 94        </property>
 95        <property name="sizeHint" stdset="0">
 96         <size>
 97          <width>348</width>
 98          <height>20</height>
 99         </size>
100        </property>
101       </spacer>
102      </item>
103      <item>
104       <widget class="QPushButton" name="both_start_pushButton">
105        <property name="text">
106         <string>Both_start_PushButton</string>
107        </property>
108       </widget>
109      </item>
110     </layout>
111    </item>
112   </layout>
113  </widget>
114  <resources/>
115  <connections/>
116 </ui>

producer_consumer_dialog.h 文件:

  1 #ifndef PRODUCER_CONSUMER_DIALOG_H
  2 #define PRODUCER_CONSUMER_DIALOG_H
  3 
  4 #include <QDialog>
  5 #include <QThread>
  6 
  7 QT_BEGIN_NAMESPACE
  8 class Producer_move_to_thread;
  9 class Consumer_move_to_thread;
 10 class Producer_table_model;
 11 //class QCloseEvent;
 12 QT_END_NAMESPACE
 13 
 14 namespace Ui {
 15 class Producer_consumer_dialog;
 16 }
 17 
 18 /*****************************************************************************************
 19   @copyright 2013-2020
 20   @author    qiaowei
 21   @contact   weiweiqiao@126.com
 22   @version   1.0
 23   @date      2021-01-27
 24   @brief     创建主窗口,生成创造者producer,并在子线程-1生产资源。生成消费者consumer,并在子线程-2消耗生
 25              产资源。资源均存储在BUFFER[]中
 26 ******************************************************************************************/
 27 class Producer_consumer_dialog : public QDialog
 28 {
 29     Q_OBJECT
 30 
 31 public:
 32     explicit Producer_consumer_dialog(QWidget *parent = nullptr);
 33     ~Producer_consumer_dialog();
 34 
 35 protected:
 36     virtual void closeEvent(QCloseEvent* ev);
 37 
 38 private:
 39     /***************************************************************************
 40      @author   qiaowei
 41      @contact  weiweiqiao@126.com
 42      @version  1.0
 43      @date     2021-01-27
 44      @brief    初始化窗体控件
 45     ***************************************************************************/
 46     void init_widgets();
 47 
 48     /***************************************************************************
 49      @author   qiaowei
 50      @contact  weiweiqiao@126.com
 51      @version  1.0
 52      @date     2021-01-27
 53      @brief    初始化私有变量,将producer_,consumer_放入各自的子线程
 54     ***************************************************************************/
 55     void init_instances();
 56 
 57     /***************************************************************************
 58      @author   qiaowei
 59      @contact  weiweiqiao@126.com
 60      @version  1.0
 61      @date     2021-01-27
 62      @brief    实例化信号槽
 63     ***************************************************************************/
 64     void init_connections();
 65 
 66 private slots:
 67     /***************************************************************************
 68      @author   qiaowei
 69      @contact  weiweiqiao@126.com
 70      @version  1.0
 71      @date     2021-01-27
 72      @brief    将字符串content设置到文本框producer_plainTextEdit
 73      @param    content 字符串
 74     ***************************************************************************/
 75     void set_producer_plain_text(quint32 serial_number, quint64 thread_id, char ch);
 76 
 77     /***************************************************************************
 78      @author   qiaowei
 79      @contact  weiweiqiao@126.com
 80      @version  1.0
 81      @date     2021-01-27
 82      @brief    将字符串content设置到文本框consumer_plainTextEdit
 83      @param    content 字符串
 84     ***************************************************************************/
 85     void set_consumer_plain_text(QString content);
 86 
 87 private:
 88     Ui::Producer_consumer_dialog *ui;
 89 
 90     Producer_move_to_thread* producer_;
 91     Consumer_move_to_thread* consumer_;
 92 
 93     QThread producer_thread_;
 94     QThread consumer_thread_;
 95 
 96     /***************************************************************************
 97      @author   qiaowei
 98      @contact  weiweiqiao@126.com
 99      @version  1.0
100      @date     2021-01-28
101      @brief    消费者产生数据对应的模型
102     ***************************************************************************/
103     Producer_table_model* producer_table_model_;
104 };
105 
106 #endif // PRODUCER_CONSUMER_DIALOG_H

producer_consumer_dialog.cpp文件:

  1 #include "producer_consumer_dialog.h"
  2 #include "ui_producer_consumer_dialog.h"
  3 
  4 #include "producer_move_to_thread.h"
  5 #include "consumer_move_to_thread.h"
  6 #include "producer_table_model.h"
  7 
  8 Producer_consumer_dialog::Producer_consumer_dialog(QWidget *parent) :
  9     QDialog(parent),
 10     ui(new Ui::Producer_consumer_dialog)
 11 {
 12     ui->setupUi(this);
 13 
 14     init_widgets();
 15     init_instances();
 16     init_connections();
 17 }
 18 
 19 Producer_consumer_dialog::~Producer_consumer_dialog()
 20 {
 21     delete producer_;
 22     delete consumer_;
 23     delete producer_table_model_;
 24 

																				
															

推荐阅读