Merge branch 'master' of gitee.com:deepin-community-store/spark-qt-demo into master
This commit is contained in:
		
						commit
						1b9df2486f
					
				
							
								
								
									
										73
									
								
								ThreadPool/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								ThreadPool/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
			
		||||
# This file is used to ignore files which are generated
 | 
			
		||||
# ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
*~
 | 
			
		||||
*.autosave
 | 
			
		||||
*.a
 | 
			
		||||
*.core
 | 
			
		||||
*.moc
 | 
			
		||||
*.o
 | 
			
		||||
*.obj
 | 
			
		||||
*.orig
 | 
			
		||||
*.rej
 | 
			
		||||
*.so
 | 
			
		||||
*.so.*
 | 
			
		||||
*_pch.h.cpp
 | 
			
		||||
*_resource.rc
 | 
			
		||||
*.qm
 | 
			
		||||
.#*
 | 
			
		||||
*.*#
 | 
			
		||||
core
 | 
			
		||||
!core/
 | 
			
		||||
tags
 | 
			
		||||
.DS_Store
 | 
			
		||||
.directory
 | 
			
		||||
*.debug
 | 
			
		||||
Makefile*
 | 
			
		||||
*.prl
 | 
			
		||||
*.app
 | 
			
		||||
moc_*.cpp
 | 
			
		||||
ui_*.h
 | 
			
		||||
qrc_*.cpp
 | 
			
		||||
Thumbs.db
 | 
			
		||||
*.res
 | 
			
		||||
*.rc
 | 
			
		||||
/.qmake.cache
 | 
			
		||||
/.qmake.stash
 | 
			
		||||
 | 
			
		||||
# qtcreator generated files
 | 
			
		||||
*.pro.user*
 | 
			
		||||
 | 
			
		||||
# xemacs temporary files
 | 
			
		||||
*.flc
 | 
			
		||||
 | 
			
		||||
# Vim temporary files
 | 
			
		||||
.*.swp
 | 
			
		||||
 | 
			
		||||
# Visual Studio generated files
 | 
			
		||||
*.ib_pdb_index
 | 
			
		||||
*.idb
 | 
			
		||||
*.ilk
 | 
			
		||||
*.pdb
 | 
			
		||||
*.sln
 | 
			
		||||
*.suo
 | 
			
		||||
*.vcproj
 | 
			
		||||
*vcproj.*.*.user
 | 
			
		||||
*.ncb
 | 
			
		||||
*.sdf
 | 
			
		||||
*.opensdf
 | 
			
		||||
*.vcxproj
 | 
			
		||||
*vcxproj.*
 | 
			
		||||
 | 
			
		||||
# MinGW generated files
 | 
			
		||||
*.Debug
 | 
			
		||||
*.Release
 | 
			
		||||
 | 
			
		||||
# Python byte code
 | 
			
		||||
*.pyc
 | 
			
		||||
 | 
			
		||||
# Binaries
 | 
			
		||||
# --------
 | 
			
		||||
*.dll
 | 
			
		||||
*.exe
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								ThreadPool/CustomThreadPool.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								ThreadPool/CustomThreadPool.pro
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
QT -= gui
 | 
			
		||||
QT += network
 | 
			
		||||
 | 
			
		||||
CONFIG += c++11 console
 | 
			
		||||
CONFIG -= app_bundle
 | 
			
		||||
 | 
			
		||||
# The following define makes your compiler emit warnings if you use
 | 
			
		||||
# any Qt feature that has been marked deprecated (the exact warnings
 | 
			
		||||
# depend on your compiler). Please consult the documentation of the
 | 
			
		||||
# deprecated API in order to know how to port your code away from it.
 | 
			
		||||
DEFINES += QT_DEPRECATED_WARNINGS
 | 
			
		||||
 | 
			
		||||
# You can also make your code fail to compile if it uses deprecated APIs.
 | 
			
		||||
# In order to do so, uncomment the following line.
 | 
			
		||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
 | 
			
		||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
 | 
			
		||||
 | 
			
		||||
SOURCES += \
 | 
			
		||||
        ThreadPool.cpp \
 | 
			
		||||
        Thread.cpp \
 | 
			
		||||
        main.cpp
 | 
			
		||||
 | 
			
		||||
# Default rules for deployment.
 | 
			
		||||
qnx: target.path = /tmp/$${TARGET}/bin
 | 
			
		||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
 | 
			
		||||
!isEmpty(target.path): INSTALLS += target
 | 
			
		||||
 | 
			
		||||
HEADERS += \
 | 
			
		||||
    PriorityQueue.h \
 | 
			
		||||
    Task.h \
 | 
			
		||||
    Thread.h \
 | 
			
		||||
    ThreadPool.h
 | 
			
		||||
							
								
								
									
										99
									
								
								ThreadPool/PriorityQueue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								ThreadPool/PriorityQueue.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <QVector>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
template <
 | 
			
		||||
        typename T,
 | 
			
		||||
        typename Array = QVector<T>,
 | 
			
		||||
        typename compare_T=std::less<T>
 | 
			
		||||
>
 | 
			
		||||
class PriorityQueue
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    PriorityQueue();
 | 
			
		||||
    bool empty();
 | 
			
		||||
    T front();
 | 
			
		||||
    void push(const T& val);
 | 
			
		||||
    void pop();
 | 
			
		||||
    int size();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void up_adjust(); // 向上调整
 | 
			
		||||
    void down_adjust(); // 向下调整
 | 
			
		||||
 | 
			
		||||
    Array elements;
 | 
			
		||||
    compare_T compare;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
PriorityQueue<T, Array, compare_T>::PriorityQueue()
 | 
			
		||||
{
 | 
			
		||||
    elements.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
bool PriorityQueue<T, Array, compare_T>::empty()
 | 
			
		||||
{
 | 
			
		||||
    return elements.size() == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
T PriorityQueue<T, Array, compare_T>::front()
 | 
			
		||||
{
 | 
			
		||||
    return elements[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
void PriorityQueue<T, Array, compare_T>::push(const T &val)
 | 
			
		||||
{
 | 
			
		||||
    elements.push_back(val);
 | 
			
		||||
    up_adjust();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
void PriorityQueue<T, Array, compare_T>::pop()
 | 
			
		||||
{
 | 
			
		||||
    if (empty()) return;
 | 
			
		||||
    int count = elements.size();
 | 
			
		||||
    qSwap(elements[count - 1], elements[0]);
 | 
			
		||||
    elements.pop_back();
 | 
			
		||||
    down_adjust();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
int PriorityQueue<T, Array, compare_T>::size()
 | 
			
		||||
{
 | 
			
		||||
    return elements.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
void PriorityQueue<T, Array, compare_T>::up_adjust()
 | 
			
		||||
{
 | 
			
		||||
    int ind = elements.size();
 | 
			
		||||
    while (ind > 1 && compare(elements[ind/2-1], elements[ind-1])) {
 | 
			
		||||
        qSwap(elements[ind/2-1], elements[ind-1]);
 | 
			
		||||
        ind /= 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename Array, typename compare_T>
 | 
			
		||||
void PriorityQueue<T, Array, compare_T>::down_adjust()
 | 
			
		||||
{
 | 
			
		||||
    int ind = 0;
 | 
			
		||||
    int count = elements.size();
 | 
			
		||||
    while (ind * 2 + 1 < count) {
 | 
			
		||||
        int tind = ind;
 | 
			
		||||
        if (compare(elements[tind], elements[ind*2+1]))
 | 
			
		||||
            tind = ind * 2 + 1;
 | 
			
		||||
 | 
			
		||||
        if (ind*2+2<count && compare(elements[tind], elements[ind*2+1]))
 | 
			
		||||
            tind = ind * 2 + 2;
 | 
			
		||||
 | 
			
		||||
        if (ind == tind)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        qSwap(elements[ind], elements[tind]);
 | 
			
		||||
        ind = tind;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								ThreadPool/Task.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								ThreadPool/Task.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
class Task
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Task(){};
 | 
			
		||||
 | 
			
		||||
    template<typename Func, typename ...Args>
 | 
			
		||||
    Task(Func f, Args&& ...args)
 | 
			
		||||
    {
 | 
			
		||||
        func = std::bind(f, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void run()
 | 
			
		||||
    {
 | 
			
		||||
        func();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setPriority(int priority)
 | 
			
		||||
    {
 | 
			
		||||
        m_priority = priority;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator<(const Task& t1, const Task& t2);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::function<void()> func;
 | 
			
		||||
    int m_priority = 100;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline bool operator<(const Task& t1, const Task& t2)
 | 
			
		||||
{
 | 
			
		||||
    return t1.m_priority < t2.m_priority;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								ThreadPool/Thread.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								ThreadPool/Thread.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
#include "Thread.h"
 | 
			
		||||
#include "ThreadPool.h"
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
Thread::Thread(int id, ThreadPool *pool, QObject *parent) :
 | 
			
		||||
    QObject(parent),
 | 
			
		||||
    m_threadPool(pool),
 | 
			
		||||
    m_id(id)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    moveToThread(&m_thread);
 | 
			
		||||
    connect(&m_thread, &QThread::started, [this](){
 | 
			
		||||
        emit threadStarted();
 | 
			
		||||
        run();
 | 
			
		||||
    });
 | 
			
		||||
    connect(&m_thread, &QThread::finished, [this](){
 | 
			
		||||
        emit threadStoped();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Thread::~Thread()
 | 
			
		||||
{
 | 
			
		||||
    if (isStarted())
 | 
			
		||||
        stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Thread::id() const
 | 
			
		||||
{
 | 
			
		||||
    return m_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Thread::start()
 | 
			
		||||
{
 | 
			
		||||
    bool ok = false;
 | 
			
		||||
    if (!isStarted()) {
 | 
			
		||||
        m_thread.start();
 | 
			
		||||
        ok = true;
 | 
			
		||||
    }
 | 
			
		||||
    return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Thread::stop()
 | 
			
		||||
{
 | 
			
		||||
    bool ok = false;
 | 
			
		||||
    if (isStarted()) {
 | 
			
		||||
        m_thread.quit();
 | 
			
		||||
        m_thread.wait();
 | 
			
		||||
        emit threadStoped();
 | 
			
		||||
        ok = true;
 | 
			
		||||
    }
 | 
			
		||||
    return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Thread::isStarted() const
 | 
			
		||||
{
 | 
			
		||||
    return m_thread.isRunning();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Thread::run()
 | 
			
		||||
{
 | 
			
		||||
    // 就是抢任务这一块出问题了,任务输入的太快
 | 
			
		||||
    while (true) {
 | 
			
		||||
        QMutexLocker lock(&(m_threadPool->m_mutex));
 | 
			
		||||
//        qDebug() << QString("线程%1 进入等待!").arg(m_id);
 | 
			
		||||
        m_threadPool->m_cond.wait(lock.mutex());
 | 
			
		||||
//        qDebug() << QString("线程%1 被唤醒!").arg(m_id);
 | 
			
		||||
        if (!m_threadPool->is_running && m_threadPool->m_tasks.empty()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        m_task = m_threadPool->m_tasks.front();
 | 
			
		||||
        m_threadPool->m_tasks.pop();
 | 
			
		||||
        m_task.run();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								ThreadPool/Thread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								ThreadPool/Thread.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
#include <QThread>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include "Task.h"
 | 
			
		||||
 | 
			
		||||
class ThreadPool;
 | 
			
		||||
 | 
			
		||||
class Thread : public QObject
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
    explicit Thread(int id = 0, ThreadPool *pool = nullptr, QObject *parent= nullptr);
 | 
			
		||||
    virtual ~Thread();
 | 
			
		||||
    virtual int id() const;
 | 
			
		||||
    virtual bool start();
 | 
			
		||||
    virtual bool stop();
 | 
			
		||||
    virtual bool isStarted() const;
 | 
			
		||||
    virtual void run();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void threadStarted();
 | 
			
		||||
    void threadStoped();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    QThread m_thread;
 | 
			
		||||
    Task m_task;
 | 
			
		||||
    ThreadPool *m_threadPool;
 | 
			
		||||
    int m_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								ThreadPool/ThreadPool.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								ThreadPool/ThreadPool.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
#include "ThreadPool.h"
 | 
			
		||||
#include "Thread.h"
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
ThreadPool::ThreadPool(size_t threads_num, QObject *parent)
 | 
			
		||||
    : QObject(parent)
 | 
			
		||||
{
 | 
			
		||||
    for (size_t i = 0; i < threads_num; i++) {
 | 
			
		||||
        m_threads.push_back(QSharedPointer<Thread>(new Thread(i, this)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThreadPool::~ThreadPool()
 | 
			
		||||
{
 | 
			
		||||
    {
 | 
			
		||||
        QMutexLocker lock(&m_mutex);
 | 
			
		||||
        is_running = false;
 | 
			
		||||
    }
 | 
			
		||||
    m_cond.wakeAll();
 | 
			
		||||
    // 等待线程退出
 | 
			
		||||
    for (auto thread : m_threads) {
 | 
			
		||||
            thread->stop();
 | 
			
		||||
    }
 | 
			
		||||
    m_threads.clear(); // 智能指针自动释放内存
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadPool::enqueue(Task &t)
 | 
			
		||||
{
 | 
			
		||||
    QMutexLocker lock(&m_mutex);
 | 
			
		||||
    if (!is_running) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    m_tasks.push(std::move(t));
 | 
			
		||||
    m_cond.wakeOne();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadPool::start()
 | 
			
		||||
{
 | 
			
		||||
    is_running = true;
 | 
			
		||||
    for (auto thread : m_threads) {
 | 
			
		||||
            thread->start();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ThreadPool::tasksCount()
 | 
			
		||||
{
 | 
			
		||||
    return m_tasks.size();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								ThreadPool/ThreadPool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								ThreadPool/ThreadPool.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "PriorityQueue.h"
 | 
			
		||||
#include "Task.h"
 | 
			
		||||
 | 
			
		||||
#include <QThread>
 | 
			
		||||
#include <QVector>
 | 
			
		||||
#include <QMutex>
 | 
			
		||||
#include <QMutexLocker>
 | 
			
		||||
#include <QWaitCondition>
 | 
			
		||||
#include <QSharedPointer>
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
 | 
			
		||||
class Thread;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using QueueType = PriorityQueue<Task>;
 | 
			
		||||
class ThreadPool : public QObject
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ThreadPool(size_t threads_num = QThread::idealThreadCount(), QObject *parent = nullptr);
 | 
			
		||||
    ~ThreadPool();
 | 
			
		||||
    void enqueue(Task& t);
 | 
			
		||||
    void start();
 | 
			
		||||
    int tasksCount();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    QVector<QSharedPointer<Thread>> m_threads;
 | 
			
		||||
    bool is_running = false;
 | 
			
		||||
    QueueType m_tasks;
 | 
			
		||||
    QMutex m_mutex;
 | 
			
		||||
    QWaitCondition m_cond;
 | 
			
		||||
 | 
			
		||||
    friend class Thread;
 | 
			
		||||
};
 | 
			
		||||
@ -1,24 +1,206 @@
 | 
			
		||||
#include "ThreadPool.hpp"
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include "ThreadPool.h"
 | 
			
		||||
 | 
			
		||||
void func(int a, int b)
 | 
			
		||||
#include <QCoreApplication>
 | 
			
		||||
#include <QMutex>
 | 
			
		||||
#include <QMutexLocker>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#include <QFileInfo>
 | 
			
		||||
#include <QtNetwork/QNetworkRequest>
 | 
			
		||||
#include <QtNetwork/QNetworkReply>
 | 
			
		||||
#include <QtNetwork/QNetworkAccessManager>
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
 | 
			
		||||
qint64 getFileSize(const QString& url);
 | 
			
		||||
void multiDownload(const QString &url, qint64 fileSize, const QString &filename);
 | 
			
		||||
 | 
			
		||||
ThreadPool pool;
 | 
			
		||||
 | 
			
		||||
QMutex mutex;
 | 
			
		||||
int count = 0;
 | 
			
		||||
 | 
			
		||||
void sum(int a, int b)
 | 
			
		||||
{
 | 
			
		||||
    std::cout << a << "+" << b << "=" << a + b << std::endl; 
 | 
			
		||||
    return;
 | 
			
		||||
    QMutexLocker lock(&mutex);
 | 
			
		||||
    count++;
 | 
			
		||||
    qDebug() << QString("%1+%2=%3").arg(a).arg(b).arg(a+b);
 | 
			
		||||
    qDebug() << QString("第%1次计算").arg(count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void event()
 | 
			
		||||
{
 | 
			
		||||
    {
 | 
			
		||||
        QMutexLocker lock(&mutex);
 | 
			
		||||
        qDebug() << "当前线程ID为:" << QThread::currentThreadId() << ",开始执行任务";
 | 
			
		||||
    }
 | 
			
		||||
    QTimer timer;
 | 
			
		||||
    QObject::connect(&timer, &QTimer::timeout, [](){
 | 
			
		||||
        QMutexLocker lock(&mutex);
 | 
			
		||||
        qDebug() << "当前线程ID为:" << QThread::currentThreadId() << ",定时器触发成功";
 | 
			
		||||
    });
 | 
			
		||||
    timer.setInterval(1000);
 | 
			
		||||
    timer.start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
    QCoreApplication a(argc, argv);
 | 
			
		||||
 | 
			
		||||
    // 测试计算任务
 | 
			
		||||
    if (false) {
 | 
			
		||||
        ThreadPool pool;
 | 
			
		||||
        pool.start();
 | 
			
		||||
        qDebug() << "线程池启动完毕,当前任务队列有任务" << pool.tasksCount();
 | 
			
		||||
        for(size_t i = 0; i < 100; i++) {
 | 
			
		||||
            Task t(sum, i, i);
 | 
			
		||||
            pool.enqueue(t);
 | 
			
		||||
        }
 | 
			
		||||
        qDebug() << "任务添加完毕,当前任务队列有任务" << pool.tasksCount();
 | 
			
		||||
        QTimer timer;
 | 
			
		||||
        QObject::connect(&timer, &QTimer::timeout, [&pool](){
 | 
			
		||||
            qDebug() << "当前任务队列有任务" << pool.tasksCount();
 | 
			
		||||
        });
 | 
			
		||||
        timer.setInterval(1000);
 | 
			
		||||
        timer.start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 测试定时器任务
 | 
			
		||||
    if (true) {
 | 
			
		||||
        pool.start();
 | 
			
		||||
        qDebug() << "线程池启动完毕,当前任务队列有任务" << pool.tasksCount();
 | 
			
		||||
        for(size_t i = 0; i < 100; i++) {
 | 
			
		||||
            Task t(event);
 | 
			
		||||
            pool.enqueue(t);
 | 
			
		||||
        }
 | 
			
		||||
        qDebug() << "任务添加完毕,当前任务队列有任务" << pool.tasksCount();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 测试下载任务
 | 
			
		||||
    if (false) {
 | 
			
		||||
        pool.start();
 | 
			
		||||
        QString url = "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_10mb.mp4";
 | 
			
		||||
        qint64 fileSize = getFileSize(url);
 | 
			
		||||
        QString filename = QFileInfo(url).fileName();
 | 
			
		||||
        multiDownload(url, fileSize, filename);
 | 
			
		||||
    }
 | 
			
		||||
    return a.exec();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 这个运行还是有点问题的,会卡顿,应该是线程退出的问题
 | 
			
		||||
 * 不像另外一个线程池,能够很快地运行   
 | 
			
		||||
 */ 
 | 
			
		||||
int main(int argc, char const *argv[])
 | 
			
		||||
 * @brief 获取要下载的文件大小
 | 
			
		||||
 * @param url
 | 
			
		||||
 */
 | 
			
		||||
qint64 getFileSize(const QString& url)
 | 
			
		||||
{
 | 
			
		||||
    std::cout << "测试输出!" << std::endl;
 | 
			
		||||
    ThreadPool<> pool(5);
 | 
			
		||||
    Task t1(func, 3, 4), t2(func, 5, 6);
 | 
			
		||||
    
 | 
			
		||||
    pool.addOneTask(&t1);
 | 
			
		||||
    pool.addOneTask(&t2);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
    QNetworkAccessManager requestManager;
 | 
			
		||||
    QEventLoop event;
 | 
			
		||||
    QNetworkRequest request;
 | 
			
		||||
    request.setUrl(QUrl(url));
 | 
			
		||||
    request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
 | 
			
		||||
    QNetworkReply *reply = requestManager.head(request);
 | 
			
		||||
    QObject::connect(reply, &QNetworkReply::errorOccurred, [reply](QNetworkReply::NetworkError error){
 | 
			
		||||
        if (error != QNetworkReply::NoError) {
 | 
			
		||||
            qDebug() << reply->errorString();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    QObject::connect(reply, &QNetworkReply::finished, &event, &QEventLoop::quit);
 | 
			
		||||
    event.exec();
 | 
			
		||||
    qint64 fileSize = 0;
 | 
			
		||||
    if (reply->rawHeader("Accept-Ranges") == QByteArrayLiteral("bytes")
 | 
			
		||||
            && reply->hasRawHeader(QString("Content-Length").toLocal8Bit())) {
 | 
			
		||||
        fileSize = reply->header(QNetworkRequest::ContentLengthHeader).toUInt();
 | 
			
		||||
    }
 | 
			
		||||
    reply->deleteLater();
 | 
			
		||||
    return fileSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief 多线程下载
 | 
			
		||||
 * @param url
 | 
			
		||||
 * @param fileSize
 | 
			
		||||
 * @param filename
 | 
			
		||||
 * @param threadCount
 | 
			
		||||
 */
 | 
			
		||||
void multiDownload(const QString &url, qint64 fileSize, const QString &filename)
 | 
			
		||||
{
 | 
			
		||||
    int threadCount = QThread::idealThreadCount();
 | 
			
		||||
 | 
			
		||||
    QFile file(filename);
 | 
			
		||||
    if (file.exists())
 | 
			
		||||
        file.remove();
 | 
			
		||||
    if (!file.open(QIODevice::WriteOnly)) {
 | 
			
		||||
        qDebug() << file.errorString();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    file.resize(fileSize);
 | 
			
		||||
 | 
			
		||||
    // 任务等分
 | 
			
		||||
    qint64 segmentSize = fileSize / threadCount;
 | 
			
		||||
    QVector<QPair<qint64, qint64>> vec(threadCount);
 | 
			
		||||
    for (int i = 0; i < threadCount; i++) {
 | 
			
		||||
        vec[i].first = i * segmentSize;
 | 
			
		||||
        vec[i].second = i * segmentSize + segmentSize - 1;
 | 
			
		||||
    }
 | 
			
		||||
    vec[threadCount-1].second = fileSize; // 余数部分加入最后一个
 | 
			
		||||
 | 
			
		||||
    qint64 bytesReceived = 0; // 下载接收的总字节数
 | 
			
		||||
 | 
			
		||||
    QMutex mutex;
 | 
			
		||||
 | 
			
		||||
    auto writeFile = [&](qint64 pos, QByteArray data){
 | 
			
		||||
        QMutexLocker lock(&mutex);
 | 
			
		||||
        qDebug() << QString("跳转文件位置%1,写入数据%2").arg(pos).arg(data.size());
 | 
			
		||||
        file.seek(pos);
 | 
			
		||||
        file.write(data);
 | 
			
		||||
        bytesReceived += data.size();
 | 
			
		||||
        if (fileSize == bytesReceived) {
 | 
			
		||||
            file.close();
 | 
			
		||||
            qDebug() << "下载完毕";
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 任务队列
 | 
			
		||||
    auto downloadFunc = [writeFile, url](const QPair<qint64, qint64>& pair) {
 | 
			
		||||
        qDebug() << QString("当前线程ID") << QThread::currentThreadId();
 | 
			
		||||
        QNetworkAccessManager *mgr = new QNetworkAccessManager;
 | 
			
		||||
        QNetworkRequest request;
 | 
			
		||||
        request.setUrl(url);
 | 
			
		||||
        request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
 | 
			
		||||
        request.setRawHeader("Range", QString("bytes=%1-%2").arg(pair.first).arg(pair.second).toLocal8Bit());
 | 
			
		||||
        QNetworkReply *reply = mgr->get(request);
 | 
			
		||||
        qint64 writePos = pair.first;
 | 
			
		||||
        qint64 currentReceived = 0;
 | 
			
		||||
        qDebug() << "开始下载数据:" << QString(" %1~%2 ").arg(pair.first).arg(pair.second);
 | 
			
		||||
        QObject::connect(reply, &QNetworkReply::readyRead, [reply, writePos, writeFile, ¤tReceived](){
 | 
			
		||||
            qDebug() << "测试,呜啦啦啦啦";
 | 
			
		||||
            qDebug() << "当前 currentReceived 的值为:" << currentReceived;
 | 
			
		||||
            qDebug() << QString("没有任何响应吗? writePos = %1, currentReceived=%2").arg(writePos).arg(currentReceived);
 | 
			
		||||
            QByteArray data = reply->readAll();
 | 
			
		||||
            writeFile(writePos + currentReceived, data);
 | 
			
		||||
            currentReceived += data.size();
 | 
			
		||||
        });
 | 
			
		||||
        QObject::connect(reply, &QNetworkReply::finished, [](){
 | 
			
		||||
            qDebug() << "线程" << QThread::currentThreadId() << "下载完毕";
 | 
			
		||||
        });
 | 
			
		||||
        QObject::connect(reply, &QNetworkReply::errorOccurred, [reply](QNetworkReply::NetworkError error){
 | 
			
		||||
            qDebug() << "发生了错误,呜啦啦啦" << reply->errorString();
 | 
			
		||||
        });
 | 
			
		||||
        QObject::connect(reply, &QNetworkReply::finished, mgr, &QNetworkAccessManager::deleteLater);
 | 
			
		||||
        // 测试事件循环
 | 
			
		||||
        QTimer timer;
 | 
			
		||||
        timer.setInterval(1000);
 | 
			
		||||
        timer.start();
 | 
			
		||||
        QObject::connect(&timer, &QTimer::timeout, [](){
 | 
			
		||||
            qDebug() << "的确有触发事件循环,可喜可贺!";
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
    qDebug() << QString("主线程ID") << QThread::currentThreadId();
 | 
			
		||||
    for (auto &pair : vec) {
 | 
			
		||||
        qDebug() << "输入任务数据,耶耶耶!";
 | 
			
		||||
        Task t(downloadFunc, pair);
 | 
			
		||||
        pool.enqueue(t);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user