一、新建一个线程类
继承QThread的一个线程类,实现run方法,同时要包含头文件
#include
获取当前的线程id
currentThreadId()
线程睡眠(1秒)
sleep(1) 或msleep(1000) 或msleep(1000000)
线程优先级
setPriority()
线程让道
yieldCurrentThread()
线程终止
terminate()
线程开启
start()
线程等待
wait()
二、线程互斥
QMutex mt,通过lock与unlock来控制
QMutexLocker locker(&mt)
// 生产者消费者模式,即信号模式
QSemaphore freeBytes(80);
QSemaphore usedBytes(0);// 利用等待和唤醒来控制
三、多线程下载小说
1、mainwindow文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#pragma execution_character_set("utf-8")
#include
#include
#include
#include
#include
#include "leaderthread.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_viewFile_clicked();
void on_startDown_clicked();
void onFinished(QNetworkReply* reply);
public slots:
void logWrite(QString log);
void finishDown();
private:
Ui::MainWindow *ui;
QString mvpath;
QString module;
QString bqgUrl;
QString bookname;
QList pageList;
QNetworkAccessManager *netManager;
QString getSubStr(QString str,QString start_str,QString end_str,qint32 start_len,qint32 end_len);
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
bqgUrl = "http://www.biquge.com/";
netManager = new QNetworkAccessManager(this);
connect(netManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onFinished(QNetworkReply*)));
logWrite("www.biquge.com/xxx/(xxx即是小说代码)");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_viewFile_clicked()
{
QString dir = QFileDialog::getExistingDirectory(this,"选择小说的存放路径:",".",QFileDialog::ShowDirsOnly);
ui->mvpath->setText(dir);
}
void MainWindow::on_startDown_clicked()
{
mvpath = ui->mvpath->text();
if(mvpath.isEmpty()){
QMessageBox::warning(this,"错误","下载路径不能为空!");return;
}
module = ui->module->text();
if(module.isEmpty()){
QMessageBox::warning(this,"错误","小说代号不得为空!");return;
}
netManager->get(QNetworkRequest(QUrl(bqgUrl+module)));
ui->startDown->setEnabled(false);
}
void MainWindow::onFinished(QNetworkReply* reply)
{
pageList.clear();
QByteArray arr = reply->readAll();
QString content(arr);
QRegExp rx("/"+module+"/[0-9]{7,9}.html");
qint32 startPos = 0;
qint32 pos = content.indexOf(rx,startPos);
while( pos >= 0){
pageList.append(rx.cap(0));
pos = content.indexOf(rx,pos + rx.matchedLength());
}
reply->deleteLater();
LeaderThread * leader = new LeaderThread();
leader->setList(pageList);
leader->setParam(this,bqgUrl+module+"/",mvpath);
leader->setBookName(getSubStr(content,"","",51,0));
leader->start();
}
void MainWindow::logWrite(QString log)
{
ui->log->append(log);
}
QString MainWindow::getSubStr(QString str,QString start_str,QString end_str,qint32 start_len,qint32 end_len)
{
qint32 pos_start = str.indexOf(QRegExp(start_str),0);
if(pos_start == -1){
return "";
}
qint32 pos_end = str.indexOf(QRegExp(end_str),pos_start);
if(pos_end == -1){
return "";
}
return str.mid(pos_start+start_len,pos_end-end_len-pos_start-start_len);
}
void MainWindow::finishDown()
{
ui->startDown->setEnabled(true);
}
2、开辟一个管理下载的线程LeaderThread
#ifndef LEADERTHREAD_H
#define LEADERTHREAD_H
#include
#include "mainwindow.h"
#include "downloadthread.h"
#include
#pragma execution_character_set("utf-8")
class LeaderThread : public QThread
{
Q_OBJECT
public:
LeaderThread();
void setList(QList& list);
void setParam(QMainWindow* wnd,QString baseUrl,QString path);
void setBookName(QString bookname);
signals:
void sendLog(QString log);
void finishDown();
protected:
void run();
void openMuchTread(qint32 n,qint32 start_pos);
private:
QList m_list;
QMainWindow* wnd;
QString baseUrl;
QString path;
QString bookname;
};
#endif // LEADERTHREAD_H
#include "leaderthread.h"
LeaderThread::LeaderThread()
{
}
void LeaderThread::run()
{
QDir dir(path+"/tmp");
if(!dir.exists()){
dir.mkdir(path+"/tmp");
}
QString filename = path + "/" + bookname + ".txt";
if(QFile::exists(filename)){
QFile::remove(filename);
}
connect(this,SIGNAL(sendLog(QString)),wnd,SLOT(logWrite(QString)));
connect(this,SIGNAL(finishDown()),wnd,SLOT(finishDown()));
qint32 listSize = m_list.size();
for(qint32 i = 0;i < listSize ; i=i+25){
if((listSize-i)>0 && (listSize-i) < 25){
openMuchTread(listSize-i,i);
}else{
openMuchTread(25,i);
}
}
QFile file(filename);
if(!file.open(QFile::WriteOnly|QFile::Truncate)){
sendLog("小说全集打包失败,文件打开失败");return;
}
for(QString item : m_list){
QFile tmpfile(path + "/tmp/" + item);
if(!tmpfile.open(QFile::ReadOnly)){
sendLog("文件没有打开:"+item);return;
}
file.write(tmpfile.readAll());
file.write("\r\n\r\n\r\n");
tmpfile.close();
QFile::remove(path + "/tmp/" + item);
sendLog("打包临时文件:"+item);
}
file.close();
dir.rmdir(path + "/tmp");
QString logInfo;
logInfo = QString("打包完成,共下载了%1章").arg(m_list.size());
sendLog(logInfo);
finishDown();
quit();
}
void LeaderThread::setList(QList& list)
{
for(QString item : list){
int pos = item.indexOf(QRegExp("/"),1);
QString newStr = item.mid(pos+1,7);
if(!m_list.contains(newStr))
m_list.append(newStr);
}
qSort(m_list.begin(),m_list.end());
}
void LeaderThread::setParam(QMainWindow* wnd,QString baseUrl,QString path)
{
this->wnd = wnd;
this->baseUrl = baseUrl;
this->path = path;
}
void LeaderThread::openMuchTread(qint32 n,qint32 start_pos)
{
QList downlist;
for(qint32 i = 0 ;i < n ;++i){
QString page = m_list.at(start_pos + i);
DownloadThread* downThread = new DownloadThread(wnd,baseUrl,page,path);
downlist.append(downThread);
downThread->start();
}
for(DownloadThread* tr : downlist){
tr->wait(10000);
}
downlist.clear();
}
void LeaderThread::setBookName(QString bookname){
this->bookname = bookname;
}
3、单个下载的线程DownloadThread
#ifndef DOWNLOADTHREAD_H
#define DOWNLOADTHREAD_H
#include
#include
#include "mainwindow.h"
#pragma execution_character_set("utf-8")
class DownloadThread : public QThread
{
Q_OBJECT
public:
DownloadThread();
DownloadThread(QMainWindow* wnd,QString baseUrl,QString page,QString path);
protected:
void run();
QString getContent(QString html);
QString getSubStr(QString str,QString start_str,QString end_str,qint32 start_len,qint32 end_len);
signals:
void sendLog(QString log);
private:
QMainWindow* wnd;
QString baseUrl;
QString page;
QString path;
};
#endif // DOWNLOADTHREAD_H
#include "downloadthread.h"
DownloadThread::DownloadThread()
{
}
DownloadThread::DownloadThread(QMainWindow* wnd,QString baseUrl,QString page,QString path)
{
this->wnd = wnd;
this->baseUrl = baseUrl;
this->page = page;
this->path = path;
}
void DownloadThread::run()
{
connect(this,SIGNAL(sendLog(QString)),wnd,SLOT(logWrite(QString)));
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(baseUrl + page + ".html")));
QEventLoop eventLoop;
connect(reply,SIGNAL(finished()),&eventLoop,SLOT(quit()));
eventLoop.exec();
QByteArray arr = reply->readAll();
QFile file(path + "/tmp/" + page);
if(!file.open(QFile::WriteOnly))
{
sendLog("存储页面"+page+"失败");
return;
}
QString html(arr);
QString content = getContent(html);
file.write(content.toUtf8());
file.close();
delete reply;
delete manager;
quit();
}
QString DownloadThread::getSubStr(QString str,QString start_str,QString end_str,qint32 start_len,qint32 end_len)
{
qint32 pos_start = str.indexOf(QRegExp(start_str),0);
if(pos_start == -1){
return "";
}
qint32 pos_end = str.indexOf(QRegExp(end_str),pos_start);
if(pos_end == -1){
return "";
}
return str.mid(pos_start+start_len,pos_end-end_len-pos_start-start_len);
}
QString DownloadThread::getContent(QString html)
{
QString title = getSubStr(html,"","",34,0);
QString content = getSubStr(html,"","",43,70);
content.replace(QRegExp(" ")," ");
content.replace(QRegExp("
"),"\r\n");
sendLog("下载完成:" + title);
return title + "\r\n\r\n" + content;
}