窃取任务队列 steal thread pool

本文介绍了一种使用互斥锁保护的同步双端队列(sync_deque)模板类,以及基于该数据结构实现的worker_t工作线程类和thread_pool线程池类。这些类支持任务的线程安全分配和执行,包括从队列中分配任务、检查队列是否为空、获取队列大小等操作。
#include <time.h>
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <functional>
#include <algorithm>
#include <deque>
#include <memory>
#include <chrono>
#include <atomic>
template <class T>
class sync_deque final {
public:
    sync_deque() = default;
	~sync_deque() = default;
	void push_front(const T &val) {
		std::unique_lock<std::mutex>lk(lock_);
		deque_.push_front(val);
	}
    T pop_front() {
        std::unique_lock<std::mutex>lk(lock_);
		if (true == deque_.empty()) {
			return nullptr;
		}
		T val = deque_.front();
		deque_.pop_front();
		return val;
	}
	T pop_back() {
        std::unique_lock<std::mutex>lk(lock_);
		if (true == deque_.empty()) {
			return nullptr;
		}
		T val = deque_.back();
		deque_.pop_back();
		return val;
	}
	inline bool empty() {
		return true == deque_.empty();
	}
    inline size_t get_size() {
        std::unique_lock<std::mutex>l(lock_);
		return deque_.size();
    }
private:
	std::deque<T>deque_;
	std::mutex lock_;
};
class worker_t;
using workers_ptr = std::shared_ptr<std::vector<std::shared_ptr<worker_t>>>;
using task_t = std::function<void()>;
class worker_t final {
public:
    explicit worker_t(workers_ptr workers, size_t work_num) : workers_(workers) {
        work_num_ = work_num;
        enabled_ = true;
        thd_ = std::thread(std::bind(&worker_t::execute, this));
    }
    inline void assign(const task_t &task) {
        queue_.push_front(task);
    }
    inline bool empty() {
        return true == queue_.empty();
    }
    inline task_t steal() {
        return queue_.pop_back();
    }
    void join() {
        enabled_ = false;
        if (thd_.joinable()) {
            std::cout << "thread join." << std::endl;
            thd_.join();
        }
    }
private:
    void execute_stealed_task() {
        int rand_select = rand() % work_num_;
        auto worker = workers_->at(rand_select);
        std::cout << rand_select << " work thread will be selected." << std::endl;
        auto task = worker->steal();
        if (nullptr != task) {
            task();
        }
    }
    void execute() {
        thread_id_ = std::this_thread::get_id();
        std::cout << "thread id = " << thread_id_ << std::endl;
        while (enabled_) {
            if (work_num_ != workers_->size()) {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            }
            task_t task = queue_.pop_front();
			while (task != nullptr) {
				task();
				task = queue_.pop_front();
			}
            bool no_task = std::all_of(workers_->begin(), workers_->end(), [] (std::shared_ptr<worker_t> worker) { return worker->empty(); });
            if (true == no_task) {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            }
            execute_stealed_task();
        }
    }
private:
    size_t work_num_;
    bool enabled_;
    std::thread thd_;
    workers_ptr workers_;
    std::thread::id thread_id_;
    sync_deque<task_t>queue_;
};
class thread_pool {
public:
    thread_pool(size_t thread_num = std::thread::hardware_concurrency()) {
        std::srand(time(nullptr));
        workers_ = std::make_shared<std::vector<std::shared_ptr<worker_t>>>();
        for (int i = 0;i < thread_num;i++) {
            auto worker = std::make_shared<worker_t>(workers_, thread_num);
            workers_->emplace_back(worker);
        }
    }
    ~thread_pool() {
        for (auto worker : *workers_) {
            worker->join();
        }
        workers_->clear();
    }
    inline void add_task(const task_t &task) {
        auto worker = get_rand_worker();
        worker->assign(task);
    }
private:
    inline std::shared_ptr<worker_t> get_rand_worker() {
        static size_t size = workers_->size();
        return workers_->at(rand() % size);
    }
private:
    workers_ptr workers_;
};
std::atomic<int>global_num;
int main() {
    thread_pool pool;
    for(size_t i = 0; i < 100; i++) {
        pool.add_task([] {
            ++global_num;
            std::cout << "global num = " << global_num.load() << std::endl;            
        });
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值