您的位置:首页 > 编程语言 > Qt开发

Qt下QThread用法学习之多线程

2012-11-21 09:12 260 查看
本文参考了http://mobile.51cto.com/symbian-272733_1.htm和http://mobile.51cto.com/symbian-268690_1.htm两篇好文章,这个两篇文章各有不足,第一篇解释QThread线程工作的原理,但是没有具体直观的多线程实例,第二篇则给出了多线程服务器端建立的实例,但是多线程并没有真正的在不同的线程工作,本文依据第一篇博文,在第二篇的基础上修改,从debug的结果来看,实现了文件在新线程中运行,真正实现了多线程。代码如下:

多线程服务器端程序(完整的)

//tcpserver.h

#ifndef TCPSERVER_H

#define TCPSERVER_H

#include "tcpthread.h"

#include<QTcpServer>

class TcpServer:public QTcpServer

{

Q_OBJECT

public:

explicit TcpServer(QObject *parent=0);

//Object obj;

signals://更新UI

void bytesArrived(qint64,qint32,int);

protected:

void incomingConnection(int socketDescriptor);

};

#endif

//tcpserver.cpp

#include "tcpserver.h"

TcpServer::TcpServer(QObject *parent):

QTcpServer(parent)

{

}

//在incomingConnection中新建一个tcpsocket线程,并完成相应的信号连接。

void TcpServer::incomingConnection(int socketDescriptor)

{

TcpThread *thread=new TcpThread(socketDescriptor,this);

qDebug()<<"server thread:"<<QThread::currentThreadId();

connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));//关闭线程

connect(thread,SIGNAL(bytesArrived(qint64,qint32,int)),this,SIGNAL(bytesArrived(qint64,qint32,int)));//接收数据

thread->start();

}

#ifndef TCPTHREAD_H

#define TCPTHREAD_H

#include <QThread>

#include<QTcpSocket>

#include<QtNetwork>

class QFile;

class QTcpSocket;

class Object:public QObject {

Q_OBJECT

public: Object(int socketDescriptor);

public:

int socketDescriptor;

qint64 bytesReceived;

qint64 byteToRead;

qint32 TotalBytes;

QTcpSocket *tcpSocket;

QHostAddress fileNameIp;//文件名Ip部分

QFile *localFile;

QByteArray inBlock;//读取缓存

signals:

void error(QTcpSocket::SocketError socketError);

void bytesArrived(qint64,qint32,int);

void receiveSgl(QTcpSocket*);

public slots:

void receiveFile();

};

class TcpThread:public QThread

{

Q_OBJECT

public:

TcpThread(int socketDescriptor,QObject *parent);

~TcpThread();

void run();

public slots:

//void receiveFile();

signals:

void bytesArrived(qint64,qint32,int);

private:

int socketDescriptor;

//Object obj;

};

#endif

#include "tcpthread.h"

#include<QtGui>

#include<QtNetwork>

TcpThread::TcpThread(int socketDescriptor,QObject *parent):

QThread(parent),socketDescriptor(socketDescriptor)

{

//bytesReceived=0;

//QObject::connect(this, SIGNAL(receiveSgl(QTcpSocket*)), &obj, SLOT(slot(QTcpSocket*)));

}

Object::Object(int socketDescriptor):socketDescriptor(socketDescriptor)

{

tcpSocket=new QTcpSocket;

bytesReceived=0;

if(!tcpSocket->setSocketDescriptor(socketDescriptor)){

emit error(tcpSocket->error());

return;

}

qDebug()<<socketDescriptor;

QObject::connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(receiveFile()));

}

TcpThread::~TcpThread()

{

quit();

wait();

deleteLater();

}

void TcpThread::run()

{

Object obj2(socketDescriptor);

obj2.moveToThread(this);

QObject::connect(&obj2,SIGNAL(bytesArrived(qint64,qint32,int)),this,SIGNAL(bytesArrived(qint64,qint32,int)),

Qt::BlockingQueuedConnection);//接收数据

// qDebug()<<socketDescriptor;

////这是重中之重,必须加Qt::BlockingQueuedConnection!

//这里困扰了我好几天,原因就在与开始没加,默认用的Qt::AutoConnection。

//简单介绍一下QT信号与槽的连接方式:

//Qt::AutoConnection表示系统自动选择相应的连接方式,如果信号与槽在同一线程,就采用Qt::DirectConnection,

//如果信号与槽不在同一线程,将采用Qt::QueuedConnection的连接方式。

//Qt::DirectConnection表示一旦信号产生,立即执行槽函数。

//Qt::QueuedConnection表示信号产生后,将发送Event给你的receiver所在的线程,postEvent(QEvent::MetaCall,...),

//slot函数会在receiver所在的线程的event loop中进行处理。

//Qt::BlockingQueuedConnection表示信号产生后调用sendEvent(QEvent::MetaCall,...),

//在receiver所在的线程处理完成后才会返回;只能当sender,receiver不在同一线程时才可以。

//Qt::UniqueConnection表示只有它不是一个重复连接,连接才会成功。如果之前已经有了一个链接(相同的信号连接到同一对象的同一个槽上),那么连接将会失败并将返回false。

//Qt::AutoCompatConnection与QT3保持兼容性

//说明一下,对于任何的QThread来说,其线程只存在于run()函数内,其它的函数都不在线程内,所以此处要采用Qt::BlockingQueuedConnection,

//因为当SOCKET有数据到达时就会发出readyRead()信号,但是此时可能之前的receiveFile()还未执行完毕,之前使用的Qt::AutoConnection,

//结果传输大文件的时候就会出错,原因就在于只要有数据到达的时候,就会连接信号,但是数据接收还没处理完毕,而Qt::BlockingQueuedConnection会阻塞

//此连接,直到receiveFile()处理完毕并返回后才发送信号。

qDebug()<<"run thread:"<<QThread::currentThreadId();

//connect(tcpSocket,SIGNAL(readyRead()),this,SIGNAL(receiveSgl(tcpSocket)));

// connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(receiveFile()),Qt::BlockingQueuedConnection);

exec();

}

void Object::receiveFile()

{

qDebug()<<"obj thread:"<<QThread::currentThreadId();

QDataStream in(tcpSocket);

if(bytesReceived<sizeof(qint32))

{

if(tcpSocket->bytesAvailable()>=sizeof(qint32))

{

in.setByteOrder(QDataStream::LittleEndian);//linux系统是大端

in>>TotalBytes;

TotalBytes+=4;

qDebug()<<TotalBytes;

bytesReceived+=sizeof(qint32);

fileNameIp = tcpSocket->peerAddress();

quint16 port = tcpSocket->peerPort();

localFile = new QFile(fileNameIp.toString()+(tr(".%1").arg(port))) ;

if(!localFile->open(QFile::WriteOnly))

{

}

}

}

if(bytesReceived<TotalBytes){

byteToRead=tcpSocket->bytesAvailable();

bytesReceived+=byteToRead;

inBlock=tcpSocket->readAll();

qDebug()<<"BytesReceived is :"<<bytesReceived;

localFile->write(inBlock);

inBlock.resize(0);

}

emit bytesArrived(bytesReceived,TotalBytes,socketDescriptor);

if(bytesReceived==TotalBytes){

localFile->close();

qDebug()<<bytesReceived;

//emit TcpThread::finished();

QApplication::restoreOverrideCursor();

}

}

#ifndef WIDGET_H

#define WIDGET_H

#include <QWidget>

#include "tcpthread.h"

#include "tcpserver.h"

class QDialogButtonBox;

class QTcpSokcet;

class QProgressBar;

class QLabel;

class QPushButton;

class QTextBrowser;

class Widget:public QWidget

{

Q_OBJECT

public:

explicit Widget(QWidget *parent = 0);

~Widget();

private:

TcpServer tcpServer;

QProgressBar *progressBar;

QPushButton *okBtn;

QPushButton *quitBtn;

QLabel *statuslabel;

QTextBrowser *textBrowser;

private slots:

void okBtnClicked();

void updateProgress(qint64,qint32,int);

};

#endif

#include "widget.h"

#include <QtNetwork>

#include <QtGui>

#include<QProgressBar>

#include<QTextBrowser>

Widget::Widget(QWidget *parent):QWidget(parent)

{

progressBar=new QProgressBar;

progressBar->setMaximum(2);

progressBar->setValue(0);

okBtn=new QPushButton("open");

quitBtn=new QPushButton("quit");

textBrowser=new QTextBrowser;

statuslabel=new QLabel(this);

qDebug()<<"main thread:"<<QThread::currentThreadId();

connect(okBtn,SIGNAL(clicked()),this,SLOT(okBtnClicked()));

QGridLayout *mainLayout=new QGridLayout;

mainLayout->addWidget(okBtn,0,0,1,1,0);

mainLayout->addWidget(quitBtn,0,1,1,1,0);

mainLayout->addWidget(textBrowser,1,0,5,2,0);

mainLayout->addWidget(progressBar,6,0,1,2,0);

mainLayout->addWidget(statuslabel,7,0,1,1,0);

setLayout(mainLayout);

}

Widget::~Widget()

{

}

void Widget::okBtnClicked()

{

okBtn->setEnabled(false);

QApplication::setOverrideCursor(Qt::WaitCursor);

while(!tcpServer.isListening()&&!tcpServer.listen(QHostAddress::Any,9001))

{

QMessageBox::StandardButton ret = QMessageBox::critical(this,tr("回环"),

tr("无法开始测试:%1.").arg(tcpServer.errorString()),QMessageBox::Retry|QMessageBox::Cancel);

if(ret==QMessageBox::Cancel)

return;

}

statuslabel->setText(tr("监听端口:%1").arg("12345"));

connect(&tcpServer,SIGNAL(bytesArrived(qint64,qint32,int)),

this,SLOT(updateProgress(qint64,qint32,int)));

}

void Widget::updateProgress(qint64 bytesReceived, qint32 TotalBytes, int socketDescriptor)

{

progressBar->setMaximum(TotalBytes);

progressBar->setValue(bytesReceived);

statuslabel->setText(tr("已接收 %1MB").arg(bytesReceived)); /// (1024 * 1024)));

textBrowser->setText(tr("现在连接的socket描述符:%1").arg(socketDescriptor));

}

#include "widget.h"

#include <QApplication>

#include<QtGui>

int main(int argc,char **argv)

{

//QTranslator oTranslator;

/*QFile file("qt_zh_CN.qm");

bool b = file.exists();

if(b)

oTranslator.load("qt_zh_CN.qm");

else

qDebug()<<"Error\n";

*/

//oTranslator.load("imagewindow_la");

QApplication app(argc,argv);

//app.installTranslator(&oTranslator);

QTextCodec::setCodecForTr(QTextCodec::codecForName("System"));

QTextCodec::setCodecForLocale(QTextCodec::codecForName("System"));

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("System"));

Widget imageWin;

imageWin.setFont(QFont("wqy-zenhei",14,QFont::Normal));

imageWin.resize(400,300);

imageWin.show();

return app.exec();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: