QT-多线程知识(例子:多线程下载小说)

一、新建一个线程类

继承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; }




你可能感兴趣的:(QT)