一个你应该学习的线程池

说明

原理:线程+优先级队列.源码没有涉及STL,没有复杂高深的语法,安全性做得很好:

  • queue的安全使用方式top和pop以及empty的判断都是使用了 std::lock_guard互斥量原子操作的保护。
  • runningNum_等变量都是std::atomic<>原子保护的
  • 数字量的自增自减,由class NumWrapper类来完成,原理与std::lock_guard类似,在构造和析构函数里完成.
  • 线程阻塞:条件变量+锁+timeout

源码

/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ #ifndef NETSTACK_THREAD_POOL
#define NETSTACK_THREAD_POOL #include <atomic>
#include <condition_variable>
#include <queue>
#include <thread>
#include <vector> namespace OHOS::NetStack {
template <typename Task, const size_t DEFAULT_THREAD_NUM, const size_t MAX_THREAD_NUM> class ThreadPool {
public:
/**
* disallow default constructor
*/
ThreadPool() = delete; /**
* disallow copy and move
*/
ThreadPool(const ThreadPool &) = delete; /**
* disallow copy and move
*/
ThreadPool &operator=(const ThreadPool &) = delete; /**
* disallow copy and move
*/
ThreadPool(ThreadPool &&) = delete; /**
* disallow copy and move
*/
ThreadPool &operator=(ThreadPool &&) = delete; /**
* make DEFAULT_THREAD_NUM threads
* @param timeout if timeout and runningThreadNum_ < DEFAULT_THREAD_NUM, the running thread should be terminated
*/
explicit ThreadPool(uint32_t timeout) : timeout_(timeout), idleThreadNum_(0), needRun_(true)
{
for (int i = 0; i < DEFAULT_THREAD_NUM; ++i) {
std::thread([this] { RunTask(); }).detach();
}
} /**
* if ~ThreadPool, terminate all thread
*/
~ThreadPool()
{
// set needRun_ = false, and notify all the thread to wake and terminate
needRun_ = false;
while (runningNum_ > 0) {
needRunCondition_.notify_all();
}
} /**
* push it to taskQueue_ and notify a thread to run it
* @param task new task to Execute
*/
void Push(const Task &task)
{
PushTask(task); if (runningNum_ < MAX_THREAD_NUM && idleThreadNum_ == 0) {
std::thread([this] { RunTask(); }).detach();
} needRunCondition_.notify_all();
} private:
bool IsQueueEmpty()
{
std::lock_guard<std::mutex> guard(mutex_);
return taskQueue_.empty();
} bool GetTask(Task &task)
{
std::lock_guard<std::mutex> guard(mutex_); // if taskQueue_ is empty, means timeout
if (taskQueue_.empty()) {
return false;
} // if run to this line, means that taskQueue_ is not empty
task = taskQueue_.top();
taskQueue_.pop();
return true;
} void PushTask(const Task &task)
{
std::lock_guard<std::mutex> guard(mutex_);
taskQueue_.push(task);
} class NumWrapper {
public:
NumWrapper() = delete; explicit NumWrapper(std::atomic<uint32_t> &num) : num_(num)
{
++num_;
} ~NumWrapper()
{
--num_;
} private:
std::atomic<uint32_t> &num_;
}; void Sleep()
{
std::mutex needRunMutex;
std::unique_lock<std::mutex> lock(needRunMutex); /**
* if the thread is waiting, it is idle
* if wake up, this thread is not idle:
* 1 this thread should return
* 2 this thread should run task
* 3 this thread should go to next loop
*/
NumWrapper idleWrapper(idleThreadNum_);
(void)idleWrapper; needRunCondition_.wait_for(lock, std::chrono::seconds(timeout_),
[this] { return !needRun_ || !IsQueueEmpty(); });
} void RunTask()
{
NumWrapper runningWrapper(runningNum_);
(void)runningWrapper; while (needRun_) {
Task task;
if (GetTask(task)) {
task.Execute();
continue;
} Sleep(); if (!needRun_) {
return;
} if (GetTask(task)) {
task.Execute();
continue;
} if (runningNum_ > DEFAULT_THREAD_NUM) {
return;
}
}
} private:
/**
* other thread put a task to the taskQueue_
*/
std::mutex mutex_;
std::priority_queue<Task> taskQueue_;
/**
* 1 terminate the thread if it is idle for timeout_ seconds
* 2 wait for the thread started util timeout_
* 3 wait for the thread notified util timeout_
* 4 wait for the thread terminated util timeout_
*/
uint32_t timeout_;
/**
* if idleThreadNum_ is zero, make a new thread
*/
std::atomic<uint32_t> idleThreadNum_;
/**
* when ThreadPool object is deleted, wait until runningNum_ is zero.
*/
std::atomic<uint32_t> runningNum_;
/**
* when ThreadPool object is deleted, set needRun_ to false, mean that all thread should be terminated
*/
std::atomic_bool needRun_;
std::condition_variable needRunCondition_;
};
} // namespace OHOS::NetStack
#endif

使用线程池

自建task类需要实现void Execute(){...}成员函数.其它的可以选择性的加,比如锁,优先级等.

/* main.cpp
* Created by 一条晓鱼ovo on 2022/12/13.
*/
#include "thread_pool.h"
#include <iostream>
#include <string> class Task {
public:
Task() = default; explicit Task(std::string context) { mContext = context; } bool operator<(const Task &e) const { return priority_ < e.priority_; } void Execute() {
std::lock_guard<std::mutex> guard(mutex_);
std::cout << "task is execute,name is:" << mContext << std::endl;
} public:
uint32_t priority_; private:
std::string mContext;
static std::mutex mutex_;
};
std::mutex Task::mutex_; #define DEFAULT_THREAD_NUM (3)
#define MAX_THREAD_NUM (4)
#define TIME_OUT (1) int test_threadpool() {
static OHOS::NetStack::ThreadPool<Task, DEFAULT_THREAD_NUM, MAX_THREAD_NUM> threadPool(TIME_OUT); Task task1("task_1");
Task task2("task_2");
Task task3("task_3");
Task task4("task_4"); threadPool.Push(task1);
threadPool.Push(task2);
threadPool.Push(task3);
threadPool.Push(task4); getchar(); threadPool.Push(task1);
threadPool.Push(task2);
threadPool.Push(task3);
threadPool.Push(task4); getchar(); return 0;
} int main() {
test_threadpool();
return 0;
}

c++11 线程池--鸿蒙OS的更多相关文章

  1. 托管C++线程锁实现 c++11线程池

    托管C++线程锁实现   最近由于工作需要,开始写托管C++,由于C++11中的mutex,和future等类,托管C++不让调用(报错),所以自己实现了托管C++的线程锁. 该类可确保当一个线程位于 ...

  2. 简单的C++11线程池实现

    线程池的C++11简单实现,源代码来自Github上作者progschj,地址为:A simple C++11 Thread Pool implementation,具体博客可以参见Jakob's D ...

  3. c++11 线程池学习笔记 (一) 任务队列

    学习内容来自一下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...

  4. C++11线程池的实现

    什么是线程池 处理大量并发任务,一个请求一个线程来处理请求任务,大量的线程创建和销毁将过多的消耗系统资源,还增加了线程上下文切换开销. 线程池通过在系统中预先创建一定数量的线程,当任务请求到来时从线程 ...

  5. c++11线程池实现

    咳咳.c++11 增加了线程库,从此告别了标准库不支持并发的历史. 然而 c++ 对于多线程的支持还是比較低级,略微高级一点的使用方法都须要自己去实现,譬如线程池.信号量等. 线程池(thread p ...

  6. c++ 11 线程池---完全使用c++ 11新特性

    前言: 目前网上的c++线程池资源多是使用老版本或者使用系统接口实现,使用c++ 11新特性的不多,最近研究了一下,实现一个简单版本,可实现任意任意参数函数的调用以及获得返回值. 0 前置知识 首先介 ...

  7. 基于C++11线程池

    1.包装线程对象 class task : public std::tr1::enable_shared_from_this<task> { public: task():exit_(fa ...

  8. 《java.util.concurrent 包源码阅读》11 线程池系列之ThreadPoolExecutor 第一部分

    先来看ThreadPoolExecutor的execute方法,这个方法能体现出一个Task被加入到线程池之后都发生了什么: public void execute(Runnable command) ...

  9. c++11线程池

    #pragma once #include <future> #include <vector> #include <atomic> #include <qu ...

  10. c++11 线程池

    也可参考: https://www.cnblogs.com/ailumiyana/p/10016965.html *** https://blog.csdn.net/jlusuoya/article/ ...

随机推荐

  1. 跳转控制语句break

    执行某些循环时,当满足了某个条件,使其提早退出循环,便可以使用break跳出循环 流程图如下: 其他循环均可以以此类推 例子:

  2. PAT (Basic Level) Practice 1007 素数对猜想 分数 20

    让我们定义dn​为:dn​=pn+1​−pn​,其中pi​是第i个素数.显然有d1​=1,且对于n>1有dn​是偶数."素数对猜想"认为"存在无穷多对相邻且差为2的 ...

  3. Git新技能-stash操作

    最近开发的工期非常紧迫,一直在忙各种杂七杂八的事情,负责人都还没有创建好测试环境, 所以代码也不能部署.可是项目经理催促开发进度又催得很急,新的开发需求必须在指定的时间内 完成,我们只得想办法去克服困 ...

  4. POC、EXP、SRC概念厘清

    「POC」 POC可以看成是一段验证的代码,就像是一个证据,能够证明漏洞的真实性,能证明漏洞的存在即可.     https://zhuanlan.zhihu.com/p/26832890 「EXP」 ...

  5. 万字详解JVM,让你一文吃透

    摘要:本文将带大家详细地了解关于JVM的一些知识点. 本文分享自华为云社区<[JVM]关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列>,作者: 冰 河 . JDK 是什么? JDK ...

  6. Java自定义排序:继承Comparable接口,重写compareTo方法(排序规则)

    代码: 1 import java.util.*; 2 3 /** 4 * 学习自定义排序:继承Comparable接口,重写compareTo方法(排序规则). 5 * TreeMap容器的Key是 ...

  7. Codeforces Round #833 (Div. 2) A-D.md

    比赛链接 A 题解 知识点:数学. 注意到 \(n\) 为奇数时,不考虑连续性,一共有 \(\lceil \frac{n}{2} \rceil ^2\) 个格子,接下来证明一定能凑成方块. 从下往上从 ...

  8. K8S节点配置资源驱逐

    #参考文章:https://www.cnblogs.com/zhangrui153169/p/15726165.html 当节点内存到达多少时.对节点的pod进行驱逐 [root@lecode-tes ...

  9. 【云原生 · Kubernetes】kubernetes v1.23.3 二进制部署(一)

    kubernetes v1.23.3 二进制部署 1. 组件版本和配置策略 1.1 主要组件版本 1.2 主要配置策略 2. 初始化系统和全局变量 2.1 集群规划 2.2 kubelet cri-o ...

  10. Guess Next Session

    打开又是一个输入框的界面,点一下下面的看源码 很简短的一个源码 大概意思是如果password等于session[password]就输出flag 直接搜了下session函数的漏洞,发现sessio ...