Giter Site home page Giter Site logo

lzpong / threadpool Goto Github PK

View Code? Open in Web Editor NEW
953.0 953.0 341.0 24 KB

based on C++11 , a mini threadpool , accept variable number of parameters 基于C++11的线程池,简洁且可以带任意多的参数

Home Page: http://www.cnblogs.com/lzpong/p/6397997.html

C++ 100.00%
mini thread-pool threadpool

threadpool's People

Contributors

lzpong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

threadpool's Issues

C++ multi-thread call python

hi,do you know how to use C++ multi-thread call python,can you help me ,thanks a lot,you can leave your email or wechat account ,my is 18811396527

发现一个BUG

如果commit函数是static的,则无法执行,请问这是为什么呢?

代码:
`
static void test(int a, int b) {
printf("a = %d, b = %d\n", a, b);
}

int main() {
std::threadpool executor;
executor.commit(test, 10, 20);
return 0;
}

`

疑惑

当任务量大于线程数吗,且当前线程没有空闲的,会有问题吗

子线程返回方式矛盾

子线程工作函数如下

while (_run)         /****** 1/
{
	Task task; // 获取一个待执行的 task
	{
		// unique_lock 相比 lock_guard 的好处是:可以随时 unlock() 和 lock()
		unique_lock<mutex> lock{ _lock };
		_task_cv.wait(lock, [this]{
				return !_run || !_tasks.empty();
		}); // wait 直到有 task
		if (!_run && _tasks.empty())  /****** 2/
			return;       
		task = move(_tasks.front()); // 按先进先出从队列取一个 task
		_tasks.pop();
	}
	_idlThrNum--;
	task();//执行任务
	_idlThrNum++;
}

由上述代码设计可见,子线程结束的方式有两种(代码中 /******/处):

  1. 第一处,当_run为false,即线程池析构时立刻停止。(这种方式结果为,当线程池析构时立刻回收所有子进程,丢弃任务队列中所有未完成任务)
  2. 第二处,要求_run为false且任务队列为空。(这种方式结果为,当线程池析构时,先完成剩下的所有任务再结束,个人认为这种设计更符合直觉)

两种方式混合使会用导致:当线程池析构时,如果任务队列还有任务,那么所有子线程会被唤醒,执行一次任务后被回收。既没有立即回收线程,也没有完全清空任务队列,就感觉挺迷惑的,如果要修改,应该使得子线程返回方式统一

  1. 要么将/****** 2/处的&&_tasks.empty()去掉,这样也就符合上面所说的第一种情况
  2. 要么将/****** 1/处的while (_run)改为while(true),这样也就符合上面所说的第二种情况

其实我认为作者是想写出第二种情况的代码的。如果这样的话/****** 1/处可能是个小bug,这会导致线程池在析构时可能会出错。

下面有个小例子可以证明我的想法。这是一个非常简单的多线程累加器,当却会导致未定义行为。
注意,该代码我在我自己的mac上用clang编译是没有问题的。但在centos上用g++编译就会出现问题,输出的结果是0,原因是线程池中的4个子线程在执行while (_run)执行前,线程池就进行析构(将_run修改为false),导致子线程直接返回,抛弃任务队列中的所有的任务,导致结果为0。(这里有个有意思的现象,我在centos上使用gdb调试来运行,结果又是正确的)可以试着在服务器上运行一下这个代码,看会不会出现相同的情况,我的环境是:CentOS Linux release 7.9.2009 (Core)g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)

#include "ThreadPool.h"
int x  = 0;
std::mutex mu;

void fun() {
    std::unique_lock<std::mutex> m{mu};
    for(int i = 0; i < 10000; i++)
        x++;
}

int main() {
    {
        std::threadpool tp;
        for(int i = 0; i < 100; i++)
            tp.commit(fun);
    }//该作用域为了析构tp,确保线程池中所有线程已经运行完
    printf("%d\n", x);   // 结果应该为 1000000
}

运行结果:
image

其实类似上面这种情况发生的概率其还挺大,只要当线程池析构的时候,任务队列中还有任务就会出现这种情况,最后会导致这种迷惑行为。
其实我猜想,作者设计那个while(_run)的判定可能是为了让线程池析构的时候,commit函数无法再创建新的子进程,但我觉得就算创建了其实也问题不大,反正可以在后面返回,不会产生不好的结果。

综上所述,我建议把第90行改成while(true)

(不知道我分析的对不对...,或者作者这样设计有别的用意?)

‘bind’ was not declared in this scope

大佬,我在本地CLION编译运行没有问题,在服务器上编译出现下面这个错误,我在网上找不到解决方法,你知道是什么愿意吗?
In file included from test.cpp:7:0:
util/threadpool.h: In instantiation of ‘std::future<decltype (f(std::threadpool::commit::args ...))> std::threadpool::commit(F&&, Args&& ...) [with F = void (&)(int); Args = {int}; decltype (f(std::threadpool::commit::args ...)) = void]’:
test.cpp:21:50: required from here
util/threadpool.h:59:17: error: ‘bind’ was not declared in this scope
bind(forward(f), forward(args)...)
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
util/threadpool.h:59:17: note: suggested alternative: ‘rand’
bind(forward(f), forward(args)...)
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
rand
In file included from test.cpp:7:0:
util/threadpool.h: In instantiation of ‘struct std::threadpool::commit(F&&, Args&& ...) [with F = void (&)(int); Args = {int}; decltype (f(std::threadpool::commit::args ...)) = void]::<lambda()>’:
util/threadpool.h:64:13: required from ‘std::future<decltype (f(std::threadpool::commit::args ...))> std::threadpool::commit(F&&, Args&& ...) [with F = void (&)(int); Args = {int}; decltype (f(std::threadpool::commit::args ...)) = void]’
test.cpp:21:50: required from here
util/threadpool.h:64:29: error: using invalid field ‘std::threadpool::commit(F&&, Args&& ...)::<lambda()>::’
_tasks.emplace(task{ // push(Task{...}) 放到队列后面

发现一个bug

理论上线程被释放之后——pool.size()应该减少一个,但是代码中没有删除_pool中元素的操作导致_pool的大小只增不减,这时如果输入压力增大线程数会因为达到上限而不开辟新线程,极端情况下甚至会导致线程清零(因为删除操作不使计数器减少导致"_pool.size() > _initSize"失效)从而没有线程执行新任务。

thread pool 与 numactl 同时使用,出现捕获不到commit的tasks

thread pool 与 numactl 同时使用,出现捕获不到commit的tasks
例如 OMP_NUM_THREADS=27 numactl --localalloc --physcpubind=0-26 捕获不到
只有 当OMP_NUM_THREADS 大于 physcpubind的时候 才可以捕获到
例如OMP_NUM_THREADS=27 numactl --localalloc --physcpubind=0-25

addThread 工作线程函数97行99行

                  unique_lock<mutex> lock{ _lock };

96 _task_cv.wait(lock, [this]{
97 return !_run || !_tasks.empty();
98 }); // wait 直到有 task
99 if (!_run && _tasks.empty())
100 return;
_tasks.empty() 为什么要判断两次呢
97 行是队列不为空就继续等待
99 行不也是队列不为空就往下

在只剩下一个空闲线程时,多个任务同时commit, 会发生什么?

这是一个race condition的情况,

#ifdef THREADPOOL_AUTO_GROW
		if (_idlThrNum < 1 && _pool.size() < THREADPOOL_MAX_NUM)
			addThread(1);
#endif // !THREADPOOL_AUTO_GROW
		_task_cv.notify_one(); // 唤醒一个线程执行

如果还有一个线程,多个commit同时发生,if 为 false, 直接执行notify, 而不会创建新的线程,有且仅有一个线程被唤醒,而且任务执行完也不判断任务队列的空与否,那么有的任务永远不会被执行。

另外,addThread里没有锁保护,下面的判断也会出错

void addThread(unsigned short size)
	{
		for (; _pool.size() < THREADPOOL_MAX_NUM && size > 0; --size)

同时调用的时候,可能poo.size 都满足,实际上已经超过max.

单例模式

上面所设计的线程池类,在工程中我们实例化一个对象就够了,是否可以设计为单例模式

编译不过

error C2447: “{”: 缺少函数标题(是否是老式的形式表?)
“threadpool”: 不是“std”的成员

关于自动释放线程的一个问题

作者您好, 您的线程池的代码第132行中提到了关于自动释放线程的问题.

if (_idlThrNum>0 && _pool.size() > _initSize) //支持自动释放空闲线程,避免峰值过后大量空闲线程
						return;

这段代码中, 您选择如果当前存在空闲线程时就会主动关闭线程. 但是这里我认为其存在一定的问题, 因为线程池中虽然该线程已经关闭, 但是仍然该线程的资源仍然在_pool中, 那么在后续的工作中, 该线程资源将不会被再次使用. 这里会不会造成一定的资源浪费的问题.

举一个比较极端的例子, 假设我吧最大线程数开到了1e5, 然后瞬间增加了1e6个任务, 这些任务都完成了之后, 显然这里会出现1e5个空闲线程, 根据这里的机制, 我们会结束前面申请的所有的线程. 但是这里开的1e5个线程仍然是占据这_pool的内存的. 如果我经常性的重复上述过程, 那显然就会造成_pool的大小越来越大, 显然这是不合理的.

请问作者, 是否已经存在一些针对该问题的解决机制(我粗心没看到).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.