一个你应该学习的线程池

说明

原理:线程+优先级队列.源码没有涉及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. 动态存储管理实战:GlusterFS

    文件转载自:https://www.orchome.com/1284 本节以GlusterFS为例,从定义StorageClass.创建GlusterFS和Heketi服务.用户申请PVC到创建Pod ...

  2. 2.Prometheus邮件报警配置

    1.安装配置 Alertmanager wget https://github.com/prometheus/alertmanager/releases/download/v0.20.0/alertm ...

  3. Android 使用压缩纹理

    本文介绍了什么是压缩纹理,以及加载压缩纹理的核心步骤.并在 Android OpenGLES 平台上实现了压缩纹理的显示. 一.压缩纹理概念 传统的图片文件格式有 PNG . JPEG 等,这种类型的 ...

  4. C++ 右值引用与 const 关键字

    C++11 新增了另一种引用:右值引用(rvalue reference),这种引用可指向右值,是使用 && 声明的.使用右值引用可以减少复制操作,延长临时对象生命周期,提升程序性能. ...

  5. struts2 标签总结

    <s:if>判断字符串的问题: 1.判断单个字符:<s:if test="#session.user.username=='c'"> 这样是从session ...

  6. NLP之基于Seq2Seq的单词翻译

    Seq2Seq 目录 Seq2Seq 1.理论 1.1 基本概念 1.2 模型结构 1.2.1 Encoder 1.2.2 Decoder 1.3 特殊字符 2.实验 2.1 实验步骤 2.2 算法模 ...

  7. 禁忌搜索算法TSA 旅行商问题TSP python

    import math import random import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot ...

  8. .NET中IActionResult的返回类型

    ActionResult继承了IActionResult JsonResult.RedirectResult.FileResult.ViewResult.ContentResult均继承了Action ...

  9. raid 5搭建部署

    raid 5搭建部署 软raid与备份 1.用四块磁盘做实验,三块盘搭建raid阵列组,有一块当作备份可以使用raid 5来搭建三块磁盘的阵列组 创建命令如下: [root@xiaohaoge ~]# ...

  10. c语言求输入的任一整数的各位数之和

    c语言求解代码: # include<stdio.h> int main(void){ int a,i=0,sum=0; scanf("%d",&a); if( ...