Qt多线程1
Qt的多线程对于设计并行程序来说很有帮助,但是多线程因为其固有的一些特性,会导致程序会出现各种隐患,尤其是类设计不好的时候尤为严重。
这里我们将详细介绍一下Qt的多线程技术,包括如何制作一个线程安全的类。
首先我们先写一个简单的例子:
首先,我们再次使用一个类DebugText ,该类继承自DebugWidget类:
#pragma once
#ifndef _DEBUGWIDGET_H__
#define _DEBUGWIDGET_H__
#include <QWidget>
#include <qtextedit.h>
#include <qlayout.h>
#include <QPainter>
class DebugWidget : public QWidget {
Q_OBJECT
public:
~DebugWidget();
protected:
DebugWidget(QWidget * parent = Q_NULLPTR);
private:
};
#endif
#include "debugwidget.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <ostream>
#include <fstream>
DebugWidget::DebugWidget(QWidget * parent) : QWidget(parent) {
//setWindowFlags(Qt::WindowStaysOnTopHint);
resize(1100,800);
//setAttribute(Qt::WA_DeleteOnClose, true);
}
DebugWidget::~DebugWidget() {
}
#include <QWidget>
#include <qtextedit.h>
#include <qlayout.h>
#include "debugwidget.hpp"
class DebugText : public DebugWidget {
Q_OBJECT
public:
~DebugText();
void addContents(const QString& s1);
static DebugText* getDebugText();
private:
QTextEdit *ShowDebugArea;
QHBoxLayout *qlayout;
DebugText(DebugWidget * parent = Q_NULLPTR);
};
extern DebugText *dt;
#endif
#include "debugtext.hpp"
#include "debugwidget.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <ostream>
#include <fstream>
static DebugText *dt = NULL;
DebugText::DebugText(DebugWidget * parent) : DebugWidget(parent) {
qlayout = new QHBoxLayout(this);
ShowDebugArea = new QTextEdit(this);
ShowDebugArea->setFontPointSize(18);
qlayout->setAlignment(Qt::AlignCenter);
qlayout->addWidget(ShowDebugArea);
show();
}
DebugText::~DebugText() {
}
void DebugText::addContents(const QString& s1)
{
ShowDebugArea->append(s1);
show();
}
DebugText* DebugText::getDebugText() {
if (dt == NULL)
dt = new DebugText;
return dt;
}
该类是自己定义的输出类,作用是开一个窗口,然后在上面显示东西。该类在前面自定义调试器的部分已经说过了。
我们的多线程方式采用继承多线程类,然后里面的run,即在另一个线程里启动的函数。注意该函数不用直接调用,直接使用QThread::start(),就会自动调用该函数。
#pragma once
#ifndef __MULTITHREAD_H__
#define __MULTITHREAD_H__
#include <QThread>
class MultiThread : public QThread {
Q_OBJECT
public:
MultiThread(QObject * parent = Q_NULLPTR);
~MultiThread();
void run();
private:
};
#include "multithread.hpp"
#include "Debugtext.hpp"
MultiThread::MultiThread(QObject * parent) : QThread(parent) {
}
MultiThread::~MultiThread() {
}
void MultiThread::run()
{
int i = 10;
while (i--) {
DebugText::getDebugText()->addContents("aaaaaaa");
}
}
注意,DebugText类只是一个普通的类,它并没有任何使用多线程的机制。
#include "multithread.hpp"
#include <QApplication>
#include "Debugtext.hpp"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MultiThread mythread;
mythread.start();
int i = 10;
while (i--) {
DebugText::getDebugText()->addContents("bbbbbb");
}
return a.exec();
}
然后运行。惊喜发生了:内存访问出错。
这是为什么呢?因为我们的DebugText的核心函数就是在TextEdit控件里添加显示字符串,而如果两个线程同时去访问了这个对象,则就会出现访问错误的情况。
我们改改主函数:
#include "multithread.hpp"
#include <QApplication>
#include "Debugtext.hpp"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MultiThread mythread;
//mythread.terminate();
int i = 10;
while (i--) {
DebugText::getDebugText()->addContents("bbbbbb");
}
mythread.start();
//QThread::sleep(100);
return a.exec();
}
这样,就可以发现,我们先打印了一堆bbbbbbb,然后又打印了一堆aaaaaaa,
但是这样好像并没有什么意义,因为我们是想同时让bbbbbbb和aaaaaaaa被打印出来。否则就是先执行一个再执行另一个,这就不是多线程了。
为了实现可以多个线程同时调用DebugText,我们必须对这个DebugText加入多线程的机制,这会在下一节进行介绍。