Qt中的QThread:使用QSemaphore进行多线程数据同步

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);

创建窗体:

Qt中的QThread:使用QSemaphore进行多线程数据同步

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 
 25     delete ui;
 26 }
 27 
 28 void Producer_consumer_dialog::closeEvent(QCloseEvent *ev)
 29 {
 30 //    QThread::sleep(3);
 31     if ( producer_thread_.isRunning()) {
 32         producer_thread_.quit();
 33         producer_thread_.wait();
 34     }
 35 
 36     if ( consumer_thread_.isRunning()) {
 37         consumer_thread_.quit();
 38         consumer_thread_.wait();
 39     }
 40 
 41     QDialog::closeEvent(ev);
 42 }
 43 
 44 void Producer_consumer_dialog::init_widgets()
 45 {
 46 //    setFixedSize(sizeHint());
 47     resize(sizeHint());
 48 }
 49 
 50 void Producer_consumer_dialog::init_instances()
 51 {
 52     producer_ = new Producer_move_to_thread();
 53     producer_->moveToThread(&producer_thread_);
 54     producer_thread_.start();
 55 
 56     consumer_ = new Consumer_move_to_thread();
 57     consumer_->moveToThread(&consumer_thread_);
 58     consumer_thread_.start();
 59 
 60     producer_table_model_ = new Producer_table_model();
 61     ui->producer_tableView->setModel(producer_table_model_);
 62 }
 63 
 64 void Producer_consumer_dialog::init_connections()
 65 {
 66     connect(ui->producer_pushButton,
 67             &QPushButton::clicked,
 68             producer_,
 69             &Producer_move_to_thread::create_char_in_thread);
 70 
 71     connect(ui->consumer_pushButton,
 72             &QPushButton::clicked,
 73             consumer_,
 74             &Consumer_move_to_thread::create_char_in_thread);
 75 
 76     connect(ui->both_start_pushButton,
 77             &QPushButton::clicked,
 78             ui->producer_pushButton,
 79             &QPushButton::clicked);
 80 
 81     connect(ui->both_start_pushButton,
 82             &QPushButton::clicked,
 83             ui->consumer_pushButton,
 84             &QPushButton::clicked);
 85 
 86     // 获取producer_生成的字符串
 87     connect(producer_,
 88             &Producer_move_to_thread::signal_index_id_content,
 89             this,
 90             &Producer_consumer_dialog::set_producer_plain_text);
 91 
 92     connect(producer_,
 93             &Producer_move_to_thread::signal_index_id_content,
 94             producer_table_model_,
 95             &Producer_table_model::add_data_to_track_list);
 96 
 97     // 获取consumer_取得的字符串
 98     connect(consumer_,
 99             &Consumer_move_to_thread::signal_string,
100             this,
101             &Producer_consumer_dialog::set_consumer_plain_text);
102 }
103 
104 void Producer_consumer_dialog::set_producer_plain_text(quint32 serial_number, quint64 thread_id, char ch)
105 {
106     QString content =
107             QString("%1: Producer thread id: %2, char: %3").
108             arg(serial_number).
109             arg(thread_id).
110             arg(ch);
111     ui->producer_plainTextEdit->appendPlainText(content);
112 //    ui->producer_plainTextEdit->setPlainText(content);
113 }
114 
115 void Producer_consumer_dialog::set_consumer_plain_text(QString content)
116 {
117     ui->consumer_plainTextEdit->appendPlainText(content);
118 //    ui->consumer_plainTextEdit->setPlaceholderText(content);
119 }

生产类

producer_move_to_thread.h 文件:

 1 #ifndef PRODUCER_MOVE_TO_THREAD_H
 2 #define PRODUCER_MOVE_TO_THREAD_H
 3 
 4 #include <QObject>
 5 
 6 /*****************************************************************************************
 7   @copyright 2013-2020
 8   @author    qiaowei
 9   @contact   weiweiqiao@126.com
10   @version   1.0
11   @date      2021-01-28
12   @brief     生产者,会被移动到子线程中产生资源
13 ******************************************************************************************/
14 class Producer_move_to_thread : public QObject
15 {
16     Q_OBJECT
17 
18 public:
19     explicit Producer_move_to_thread(QObject *parent = nullptr);
20     ~Producer_move_to_thread();
21 
22 signals:
23 //    void signal_string(quint32 serial_number, quint64 thread_id, char ch);
24 
25     void signal_index_id_content(quint32 index, int id, char ch);
26 
27 public slots:
28     void create_char_in_thread();
29 };
30 
31 #endif // PRODUCER_MOVE_TO_THREAD_H

producer_move_to_thread.CPP 文件:

 1 #include <QtDebug>
 2 #include <QThread>
 3 #include <QtGlobal>
 4 #include "producer_move_to_thread.h"
 5 #include "constant_variable.h"
 6 
 7 Producer_move_to_thread::Producer_move_to_thread(QObject* parent):
 8     QObject(parent)
 9 {
10 
11 }
12 
13 Producer_move_to_thread::~Producer_move_to_thread()
14 {
15 
16 }
17 
18 void Producer_move_to_thread::create_char_in_thread()
19 {
20     for (int index(0); DATA_SIZE != index; ++index) {
21         // 生产1个资源(总共要产生的DATA_SZIE个资源),然后保存到BUFFER数组,BUFFER数组空余位置少1个
22         PRODUCER_SPACE.acquire(1);
23 
24         // 计算获取资源序号、线程号、数据资源
25         quint32 serial_number = (quint32) (index + 1);
26         quint64 thread_id = (quint64) QThread::currentThreadId();
27         char ch = "ABCDXYZ"[uint(std::rand()) % 7];
28         BUFFER[index % BUFFER_SIZE] = ch;
29 
30         qDebug()<< "Produce thread id: " << thread_id
31                 << ", char: " <<  ch;
32 
33         // 将数据传给窗体Producer_consumer_dialog
34 //        emit signal_string(serial_number, thread_id, ch);
35 
36         emit signal_index_id_content(serial_number, thread_id, ch);
37 
38         // 线程挂起,不对主线程造成卡顿
39         QThread::usleep(10);
40 
41         // 数组中已保存1个字符,Consumer获取1个可用资源
42         CONSUMER_SPACE.release(1);
43     }
44 }

资源消耗类

consumer_move_to_thread.h 文件:

 1 #ifndef CONSUMER_MOVE_TO_THREAD_H
 2 #define CONSUMER_MOVE_TO_THREAD_H
 3 
 4 #include <QObject>
 5 
 6 class Consumer_move_to_thread : public QObject
 7 {
 8     Q_OBJECT
 9 public:
10     explicit Consumer_move_to_thread(QObject *parent = nullptr);
11 
12 signals:
13     void signal_string(QString content);
14 
15 public slots:
16     void create_char_in_thread();
17 };
18 
19 #endif // CONSUMER_MOVE_TO_THREAD_H

consumer_move_to_thread.CPP 文件:

 1 #include <QtDebug>
 2 #include <QThread>
 3 #include "consumer_move_to_thread.h"
 4 #include "constant_variable.h"
 5 
 6 Consumer_move_to_thread::Consumer_move_to_thread(QObject *parent) :
 7     QObject(parent)
 8 {
 9 
10 }
11 
12 void Consumer_move_to_thread::create_char_in_thread()
13 {
14     for (int index(0); DATA_SIZE != index; ++index) {
15         // 消耗1个资源(总共要消耗DATA_SZIE个资源),从BUFFER数组中取出,BUFFER数组空余位置多1个。当
16         // 没有资源提供时,进程被挂起,待有足够资源后再执行后续程序
17         CONSUMER_SPACE.acquire(1);
18 
19         qDebug()<< "Consumer thread id: " << (quint64) QThread::currentThreadId()
20                 << ", char: " << (char) BUFFER[index % BUFFER_SIZE];
21 
22         QString content =
23                 QString("%1: Consumer thread id: %2, char: %3").
24                 arg(index + 1).
25                 arg((quint64) QThread::currentThreadId()).
26                 arg(BUFFER[index % BUFFER_SIZE]);
27 
28         emit signal_string(content);
29         //线程挂起,不对主线程造成卡顿
30         QThread::usleep(10);
31 
32         // 使用数组中1个资源,数组释放1个空间,给生产者提供1个空余位置
33         PRODUCER_SPACE.release(1);
34     }
35 }

保存生产者生成的数据Track类:

Track.h

 1 #ifndef TRACK_H
 2 #define TRACK_H
 3 
 4 #include <QtGlobal>
 5 
 6 /*****************************************************************************************
 7   @copyright 2013-2020
 8   @author    qiaowei
 9   @contact   weiweiqiao@126.com
10   @version   1.0
11   @date      2021-01-28
12   @brief     数据类,保存随机生成的资源
13 ******************************************************************************************/
14 class Track
15 {
16 public:
17     /***************************************************************************
18      @author   qiaowei
19      @contact  weiweiqiao@126.com
20      @version  1.0
21      @date     2021-01-28
22      @brief    构造函数
23      @param    index 数据的生成序列号
24      @param    thread_id 生成数据的线程号
25      @param    ch 生成的资源数据
26     ***************************************************************************/
27     explicit Track(quint32 index = 0, quint64 thread_id = 0, char ch = 'A');
28     ~Track();
29 
30     /***************************************************************************
31      @author   qiaowei
32      @contact  weiweiqiao@126.com
33      @version  1.0
34      @date     2021-01-28
35      @brief    拷贝构造函数
36     ***************************************************************************/
37     Track(const Track& r_value);
38 
39     /***************************************************************************
40      @author   qiaowei
41      @contact  weiweiqiao@126.com
42      @version  1.0
43      @date     2021-01-28
44      @brief    赋值操作符
45     ***************************************************************************/
46     Track& operator = (const Track& r_value);
47 
48     quint32 get_index() const;
49 
50     quint64 get_thread_id() const;
51 
52     char get_char() const;
53 
54 private:
55     quint32 index_;
56     quint64 thread_id_;
57     char char_;
58 };
59 
60 #endif // TRACK_H

Track.CPP

 1 #include "track.h"
 2 
 3 
 4 Track::Track(quint32 index, quint64 thread_id, char ch):
 5     index_(index),
 6     thread_id_(thread_id),
 7     char_(ch)
 8 {
 9 
10 }
11 
12 Track::~Track()
13 {
14 
15 }
16 
17 Track::Track(const Track &r_value)
18 {
19     index_ = r_value.index_;
20     thread_id_ = r_value.thread_id_;
21     char_ = r_value.char_;
22 }
23 
24 Track &Track::operator =(const Track &r_value)
25 {
26     if (this != &r_value) {
27         index_ = r_value.index_;
28         thread_id_ = r_value.thread_id_;
29         char_ = r_value.char_;
30     }
31 
32     return *this;
33 }
34 
35 quint32 Track::get_index() const
36 {
37     return index_;
38 }
39 
40 quint64 Track::get_thread_id() const
41 {
42     return thread_id_;
43 }
44 
45 char Track::get_char() const
46 {
47     return char_;
48 }

生产者模型Produer_table_model类:

Produer_table_model.h

 1 #ifndef PRODUCER_TABLE_MODEL_H
 2 #define PRODUCER_TABLE_MODEL_H
 3 
 4 #include <QAbstractTableModel>
 5 #include <QObject>
 6 #include "track.h"
 7 
 8 /*****************************************************************************************
 9   @copyright 2013-2020
10   @author    qiaowei
11   @contact   weiweiqiao@126.com
12   @version   1.0
13   @date      2021-01-28
14   @brief
15 ******************************************************************************************/
16 class Producer_table_model : public QAbstractTableModel
17 {
18     Q_OBJECT
19 
20 public:
21     explicit Producer_table_model(QObject* parent = nullptr);
22     ~Producer_table_model();
23 
24     void add_data_to_track_list(quint32 serial_number, quint64 thread_id, char ch);
25 
26     QList<Track>* get_track_list();
27 
28 protected:
29     virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
30 
31     virtual int columnCount(const QModelIndex& parent = QModelIndex()) const;
32 
33     virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
34 
35     virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
36 
37 private:
38     QList<Track>* track_list_;
39 };
40 
41 #endif // PRODUCER_TABLE_MODEL_H

Produer_table_model.CPP

 1 #include "producer_table_model.h"
 2 
 3 Producer_table_model::Producer_table_model(QObject* parent):
 4     QAbstractTableModel(parent),
 5     track_list_(new QList<Track>())
 6 {
 7 
 8 }
 9 
10 Producer_table_model::~Producer_table_model()
11 {
12     delete track_list_;
13 }
14 
15 void Producer_table_model::add_data_to_track_list(quint32 serial_number, quint64 thread_id, char ch)
16 {
17     track_list_->append(Track(serial_number, thread_id, ch));
18 
19     QModelIndex header_model_index = createIndex(serial_number - 1, 0);
20     QModelIndex tail_model_index = createIndex(serial_number - 1, 2);
21 
22     layoutChanged();
23 }
24 
25 QList<Track> *Producer_table_model::get_track_list()
26 {
27     return track_list_;
28 }
29 
30 int Producer_table_model::rowCount(const QModelIndex &parent) const
31 {
32     Q_UNUSED(parent)
33 
34     if ( track_list_) {
35         return track_list_->count();
36     } else {
37         return 0;
38     }
39 }
40 
41 int Producer_table_model::columnCount(const QModelIndex &parent) const
42 {
43     Q_UNUSED(parent)
44 
45 //    // 序号、线程号、数据资源
46 //    return 3;
47 
48     // 线程号、数据资源
49     return 2;
50 }
51 
52 QVariant Producer_table_model::data(const QModelIndex &index, int role) const
53 {
54     if ( !index.isValid()) {
55         return QVariant();
56     }
57 
58     QVariant v;
59     if (Qt::DisplayRole == role) {
60         switch (index.column()) {
61         case 0:
62             v = track_list_->at(index.row()).get_thread_id();
63             break;
64 
65         case 1:
66             v = (QChar) track_list_->at(index.row()).get_char();
67             break;
68         }
69 
70         return v;
71     }
72 
73 
74 
75     return QVariant();
76 }
77 
78 QVariant Producer_table_model::headerData(int section, Qt::Orientation orientation, int role) const
79 {
80     if ((Qt::DisplayRole == role) &&
81             (Qt::Horizontal == orientation)) {
82 
83         QString header_content;
84         switch (section) {
85         case 0:
86             header_content = tr("线程号");
87             break;
88 
89         case 1:
90             header_content = tr("数据");
91             break;
92         }
93 
94         return header_content;
95     }
96 
97     return QAbstractTableModel::headerData(section, orientation, role);
98 }

在这里特别注意PRODUCER_SPACE和CONSUMER_SPACE的初始值,因为资源BUFFER数组初始资源为0,所以生产者Producer可用的数组空间为所有,消耗着Consumer可用的数组空间为0,因为没有资源可用。

运行结果如下图:

Qt中的QThread:使用QSemaphore进行多线程数据同步