From aebbceac74ef83e1ed7d5f3d659243eb2ca4f43d Mon Sep 17 00:00:00 2001 From: Deel Date: Fri, 6 Nov 2015 00:56:34 +0800 Subject: [PATCH] added - src/core/workers --- src/core/workers/.gitignore | 4 + src/core/workers/BUILD | 35 ++++ src/core/workers/Makefile | 41 ++++ src/core/workers/demo/.gitignore | 4 + src/core/workers/demo/Makefile | 79 ++++++++ src/core/workers/demo/test_logworkers.cpp | 81 ++++++++ src/core/workers/logworkers.cpp | 50 +++++ src/core/workers/logworkers.h | 88 ++++++++ src/core/workers/workers.h | 234 ++++++++++++++++++++++ 9 files changed, 616 insertions(+) create mode 100644 src/core/workers/.gitignore create mode 100644 src/core/workers/BUILD create mode 100644 src/core/workers/Makefile create mode 100644 src/core/workers/demo/.gitignore create mode 100644 src/core/workers/demo/Makefile create mode 100644 src/core/workers/demo/test_logworkers.cpp create mode 100644 src/core/workers/logworkers.cpp create mode 100644 src/core/workers/logworkers.h create mode 100644 src/core/workers/workers.h diff --git a/src/core/workers/.gitignore b/src/core/workers/.gitignore new file mode 100644 index 0000000..1b8c33e --- /dev/null +++ b/src/core/workers/.gitignore @@ -0,0 +1,4 @@ + +tmp +*.stackdump + diff --git a/src/core/workers/BUILD b/src/core/workers/BUILD new file mode 100644 index 0000000..d704ccc --- /dev/null +++ b/src/core/workers/BUILD @@ -0,0 +1,35 @@ +1. Build logworkers link + + target: + link/logworkers.o + + command: + e.g. + $ make Container_Type=-DLOG_PRIORITY_QUEUE + $ # Container_Type=-DLOG_PRIORITY_QUEUE # or '-DLOG_LOCKFREE_QUEUE' + + tips: + -DLOG_PRIORITY_QUEUE + Log container using 'priority queue'. + by default, it will output priority the 'FATAL' level logs + -DLOG_LOCKFREE_QUEUE + Log container using 'lockfree queue' + +2. Build demo + + target: + ./demo/bin/test_logworkers.static + ./demo/bin/test_logworkers + + commad: + e.g. + $ cd ./demo + $ make Container_Type=-DLOG_PRIORITY_QUEUE PYTHON_INCLUDE=/usr/include/python2.7 PYTHON_LIB_PATH=/usr/lib PYTHON_LIB=-lpython2.7 + tips: + PYTHON_LIB_PATH is the path to python library files, libpython2.7.so libpython2.7.a ... + default path: /usr/lib + PYTHON_LIB is '-l' option of gcc, -lpython2.7, -lpython2.7.dll ... + please using -lpython2.7.dll on Cygwin. + + + diff --git a/src/core/workers/Makefile b/src/core/workers/Makefile new file mode 100644 index 0000000..1c1d4ef --- /dev/null +++ b/src/core/workers/Makefile @@ -0,0 +1,41 @@ +CC = gcc +XX = g++ +RM = rm -rf + +PWD = $(shell pwd) +ROOT = $(PWD)/../ +LINK = ./link + +LOG_SRC = $(ROOT)/log + +CFLAGS = -Wall -D_REENTRANT $(Container_Type) -g -std=gnu++0x # win32: -std=c++11 + + +INCLUDE = -I$(ROOT)/../../contrib/boost/boost_1_57_0/ \ + -I$(ROOT)/ -I. +#STDLIB = -stdlib=libc++ # win32 + +all: init TARGET + +init: +ifndef Container_Type + $(info [ err] Container_Type not set!) + $(info [info] e.g ) + $(info [info] $$ Container_Type=-DLOG_PRIORITY_QUEUE # or '-DLOG_LOCKFREE_QUEUE') + $(info [info] $$ make ... Container_Type=$$Container_Type ...) + $(error error) +endif + [ -d '$(LINK)' ] || mkdir $(LINK) + cd $(LOG_SRC); make loglib Container_Type=$(Container_Type) + +TARGET: $(LINK)/logworkers.o + +$(LINK)/%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ +$(LINK)/%.o: %.cpp + $(XX) $(CFLAGS) $(STDLIB) $(INCLUDE) -c $< -o $@ + + +clean: + $(RM) $(LINK) + diff --git a/src/core/workers/demo/.gitignore b/src/core/workers/demo/.gitignore new file mode 100644 index 0000000..ff6e5f2 --- /dev/null +++ b/src/core/workers/demo/.gitignore @@ -0,0 +1,4 @@ +bin +~tmp +*.stackdump + diff --git a/src/core/workers/demo/Makefile b/src/core/workers/demo/Makefile new file mode 100644 index 0000000..f4e2f81 --- /dev/null +++ b/src/core/workers/demo/Makefile @@ -0,0 +1,79 @@ +CC = gcc +XX = g++ +RM = rm -rf + +PWD = $(shell pwd) +ROOT = $(PWD)/../../ +TMP = ./~tmp +BIN = ./bin + +WORKERS_SRC = $(ROOT)/workers +LOGROTATE_SRC = $(ROOT)/logrotate +PYTHON_SRC = $(ROOT)/python +EXCEPT_SRC = $(ROOT)/except +LOG_SRC = $(ROOT)/log +LOG_LIB_DIR = $(LOG_SRC)/lib + +CFLAGS = -Wall -D_REENTRANT $(Container_Type) -g -std=gnu++0x # win32: -std=c++11 + + +INCLUDE = -I$(ROOT)/../../contrib/boost/boost_1_57_0/ -I$(ROOT) +#STDLIB = -stdlib=libc++ # win32 + +BOOST_LINK_DIR = $(ROOT)/boost_build/link +BOOST_LINK = $(BOOST_LINK_DIR)/sysprebuild.o \ + $(BOOST_LINK_DIR)/dateprebuild.o \ + $(BOOST_LINK_DIR)/tprebuild.o + +ALL_LINK = $(WORKERS_SRC)/link/logworkers.o \ + $(LOGROTATE_SRC)/link/logrotate.o \ + $(PYTHON_SRC)/lib/libpyfunc.a \ + $(EXCEPT_SRC)/link/except.o \ + $(BOOST_LINK) + +LIBPATH = -L$(LOG_LIB_DIR) -L$(PYTHON_SRC)/lib +LIBS += $(LIBPATH) -llog $(PYTHON_LIB) -lpthread -lrt -ldl -lutil -lz + +all: init TARGET + +init: +ifndef Container_Type + $(info [ err] Container_Type not set!) + $(info [info] e.g ) + $(info [info] $$ Container_Type=-DLOG_PRIORITY_QUEUE # or '-DLOG_LOCKFREE_QUEUE') + $(info [info] $$ make ... Container_Type=$$Container_Type ...) + $(error error) +endif +ifndef PYTHON_INCLUDE + $(info PYTHON_INCLUDE not set !) + $(info e.g. $$ make ... PYTHON_INCLUDE=/usr/include/python2.7 ...) + $(error error) +endif +ifndef PYTHON_LIB + $(info [ err] PYTHON_LIB not set !) + $(info [info] e.g. $$ make ... PYTHON_LIB=-lpython2.7 ...) + $(error error) +endif + [ -d '$(TMP)' ] || mkdir $(TMP) + [ -d '$(BIN)' ] || mkdir $(BIN) + cd $(WORKERS_SRC); make Container_Type=$(Container_Type) USE_LOCK=-DLOG_USE_LOCK + cd $(LOGROTATE_SRC); make PYTHON_INCLUDE=$(PYTHON_INCLUDE) + + +TARGET: $(BIN)/test_logworkers $(BIN)/test_logworkers.static + +$(BIN)/test_logworkers: $(TMP)/test_logworkers.o $(ALL_LINK) + $(XX) $^ -o $@ $(LIBS) +$(BIN)/test_logworkers.static: $(TMP)/test_logworkers.o $(ALL_LINK) + $(XX) $^ -o $@ -static $(LIBS) + +$(TMP)/%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ +$(TMP)/%.o: %.cpp + $(XX) $(CFLAGS) $(STDLIB) $(INCLUDE) -c $< -o $@ + + +clean: + $(RM) $(TMP) $(BIN) + cd $(LOG_SRC); make clean + diff --git a/src/core/workers/demo/test_logworkers.cpp b/src/core/workers/demo/test_logworkers.cpp new file mode 100644 index 0000000..105b7ff --- /dev/null +++ b/src/core/workers/demo/test_logworkers.cpp @@ -0,0 +1,81 @@ +#include +#include "workers/logworkers.h" + +void produce_log() { + loginfo("thread id:[" << boost::this_thread::get_id() << "] Start..." ); + for (int i = 0; i < 5; ++i) { + logwarn("test..."); + } +} + +void test() { + using namespace std; + bool ret = LogOutput_t::get_instance().bind(cout); + cout << boolalpha << ret << endl; + + Workers& workers = LogWorkers::get_mutable_instance(); + //workers.start(2); + workers.start(3, true); + boost::this_thread::sleep_for(boost::chrono::milliseconds(1000)); + workers.interrupt_all(/*false*/); + //boost::this_thread::sleep_for(chrono::milliseconds(100)); +} + +int main(int argc, char** argv) { + produce_log(); + test(); + return 0; +} +/////////////////////////////////////////////////// + +//#include "store.h" +// +//class rw_data { +// private: +// int m_x; +// shared_mutex rw_mu; +// public: +// rw_data() : m_x(0) {} +// void write() { +// unique_lock ul(rw_mu); +// ++m_x; +// } +// void read(int *x) { +// shared_lock sl(rw_mu); +// *x = m_x; +// } +//}; +//void writer(rw_data &d) { +// for (int i = 0; i < 20; ++i) { +// this_thread::sleep_for(chrono::milliseconds(10)); +// d.write(); +// } +//} +//mutex io_mu; +//void reader(rw_data &d) { +// int x; +// for (int i = 0; i < 10; ++i) { +// this_thread::sleep_for(chrono::milliseconds(5)); +// d.read(&x); +// mutex::scoped_lock lock(io_mu); +// cout << "reader: " << x << endl; +// } +//} +//void test2() { +// rw_data d; +// thread_group pool; +// pool.create_thread(boost::bind(writer, boost::ref(d))); +// pool.create_thread(boost::bind(writer, boost::ref(d))); +// +// pool.create_thread(boost::bind(reader, boost::ref(d))); +// pool.create_thread(boost::bind(reader, boost::ref(d))); +// pool.create_thread(boost::bind(reader, boost::ref(d))); +// pool.create_thread(boost::bind(reader, boost::ref(d))); +// +// pool.join_all(); +//} +// +//int main(int argc, char** argv) { +// test2(); +// return 0; +//} diff --git a/src/core/workers/logworkers.cpp b/src/core/workers/logworkers.cpp new file mode 100644 index 0000000..98e7e2c --- /dev/null +++ b/src/core/workers/logworkers.cpp @@ -0,0 +1,50 @@ +#include "workers/logworkers.h" +#include "log/logoutput.h" // is used in the function process() +#include +#include +using namespace std; + +/* 处理中断时使用的输出流, 初始值为std::cout */ +/*static*/ostream& LogWorkers::m_interrupt_os = cout; +/* 处理日志转储所使用的Logrotate对象, 初始值为NULL */ +/*static*/Logrotate* LogWorkers::logrt = NULL; + +// 重写三个虚函数 +void LogWorkers::prepare() { + loginfo("Now start a Workers thread(id:" + << boost::this_thread::get_id() + << ", module:LogWorkers)!"); + this->val = std::make_shared(); +} + + +void LogWorkers::process() { + // 因为本身是从日志仓库里输出日志, 所以这里不能再往日志仓库扔东西 + LogOutput_t::get_instance().output_once(this->val); + + // 尝试日志转储 + if (logrt) { + logrt->action(); + } +} + +void LogWorkers::interruption_respond() { + // 因为本身是从日志仓库里输出日志, 所以这里不能再往日志仓库扔东西 + time_t timer = time(NULL); + string cur_time = asctime(localtime(&timer)); + cur_time.pop_back(); + ostringstream oss; + oss << cur_time << " [WARNING]: Workers thread(id:" + << boost::this_thread::get_id() << ", module:LogWorkers) is interrupted!" + << " [" << __FILE__ << ':' << __LINE__ << ']' << std::endl; + + // 安全输出到m_interrupt_os + auto plock = LogOutput_t::get_instance().get_lock(m_interrupt_os); + if (plock) { + LogOutput_t::scoped_lock lock(m_interrupt_os, *plock); + m_interrupt_os << oss.str(); + } + else { + m_interrupt_os << oss.str(); + } +} diff --git a/src/core/workers/logworkers.h b/src/core/workers/logworkers.h new file mode 100644 index 0000000..de757ad --- /dev/null +++ b/src/core/workers/logworkers.h @@ -0,0 +1,88 @@ +#ifndef LOGWORKERS_H +#define LOGWORKERS_H +/* + * LogWorkers 类 (工种: 日志输出) + * + * 1. 说明: 对日志输出的操作模块, 继承自Workers抽象类,单件实现 + * 2. 原型: class LogWorkers : public Workers; + * 3. 摘要: + * 1. 3个私有重写方法: + * 1. virtual void prepare(); + * 进入流程循环之前的处理函数, 用于输出进程信息和标识所在模块 + * 2. virtual void process(void); + * 一个(次)工作流程 + * 3. virtual void interruption_respond(); + * 对于工作线程中断后的响应函数, 用于将错误信息及所在模块标识 + * 输出到m_interrupt_os. 其中操作m_interrupt_os时使用了LogOut + * 中的互斥锁,避免线程冲突. + * 2. 2个公有静态成员: + * 1. static std::ostream& m_interrupt_os; + * 处理中断时使用的输出流, 会在interruption_respond()中被使用, + * 初始值为std::cout. 可用在GUI编程时对输出流重新赋值以满足需求. + * + * 2. static Logrotate* logrt; // 为NULL时不执行日志转储 + * 处理日志转储所使用的Logrotate对象指针, 初始值为NULL + * + * 4. 直接依赖: + * 1. 日志模块, 包括日志生产和LogOutput + * 2. Workers抽象类 + * 3. 日志转储模块 Logrotate + * + */ + +/////////////////////////////////////////////////////////////////////// +//example: +// +// produce_log(); // some loginfo, logwarning or logerr +// bool ret = LogOut::get_mutable_instance().bind(std::cout); +// cout << boolalpha << ret << endl; +// +// Workers& workers = LogWorkers::get_mutable_instance(); +// //workers.start(2/*, false*/); // waiting... +// workers.start(3, true); +// boost::this_thread::sleep_for(chrono::milliseconds(50)); +// workers.interrupt_all(/*false*/); // waiting... +// //boost::this_thread::sleep_for(chrono::milliseconds(100)); +// +//a possible output: +// +// true +// Wed Dec 17 20:27:52 2014 [INFO]: produce log thread[id: 0x20000038] starts [main.cpp:8] +// Wed Dec 17 20:27:52 2014 [WARNING]: test... [main.cpp:10] +// Wed Dec 17 20:27:52 2014 [WARNING]: test... [main.cpp:10] +// Wed Dec 17 20:27:52 2014 [WARNING]: test... [main.cpp:10] +// Wed Dec 17 20:27:52 2014 [WARNING]: test... [main.cpp:10] +// Wed Dec 17 20:27:52 2014 [WARNING]: test... [main.cpp:10] +// Wed Dec 17 20:27:52 2014 [INFO]: Now start a Workers thread(id:0x20014ce0, module:LogWorkers)! [logworkers.cpp:14] +// Wed Dec 17 20:27:52 2014 [INFO]: Now start a Workers thread(id:0x20015258, module:LogWorkers)! [logworkers.cpp:14] +// Wed Dec 17 20:27:52 2014 [INFO]: Now start a Workers thread(id:0x200155d8, module:LogWorkers)! [logworkers.cpp:14] +// Wed Dec 17 20:27:52 2014 [WARNING]: Workers thread(id:0x20015258, module:LogWorkers) is interrupted! [logworkers.cpp:30] +// Wed Dec 17 20:27:52 2014 [WARNING]: Workers thread(id:0x20014ce0, module:LogWorkers) is interrupted! [logworkers.cpp:30] +// Wed Dec 17 20:27:52 2014 [WARNING]: Workers thread(id:0x200155d8, module:LogWorkers) is interrupted! [logworkers.cpp:30] +// +/////////////////////////////////////////////////////////////////////// + +#include +#include "workers/workers.h" +//#include "log/logoutput.h" // is used in the function process() +#include "logrotate/logrotate.h" +#include "log/init_simple.h" + +class LogWorkers : public Workers { + public: + /* 处理中断时使用的输出流, 初始值为std::cout */ + static std::ostream& m_interrupt_os; + /* 处理日志转储所使用的Logrotate对象, 初始值为NULL */ + static Logrotate* logrt; // 为NULL时不执行日志转储 + private: + // 进入流程循环之前的处理函数 + virtual void prepare(); + // 一个工作流程 + virtual void process(void); + // 对于线程中断后的响应函数 + virtual void interruption_respond(); + LogWorkers& operator=(const LogWorkers&) = delete; + private: + std::shared_ptr val; +}; +#endif // LOGWORKERS_H diff --git a/src/core/workers/workers.h b/src/core/workers/workers.h new file mode 100644 index 0000000..449f17b --- /dev/null +++ b/src/core/workers/workers.h @@ -0,0 +1,234 @@ +#ifndef WORKER_H +#define WORKER_H + +/** + * Workers 抽象工作者类 + * + * 1. 特点: 对工人集合进行了封装; 一个工人对应一个工作线程, 不同工种由其唯一 + * 的线程池对象进行管理; 对不同工种的执行流程提供了继承接口; 不同工种由其子类 + * 实现(一个子类对应一个工种)。 + * 2. 原型: + * template + * class Workers : public boost::serialization::singleton; + * 3. 方法摘要: + * 1. void start(const count_t& n, bool return_immediately = false); + * Workers开工方法. + * 参数一为要启用的工作线程数量. + * 注意, 当n小于或等于已启用的工人数,则将不会有新的工人被创建; + * 参数二为是否立即返回, 当为false时,该函数会一直等待工人被要求 + * 中断退出后才返回, 否则一直阻塞等待. + * 2. void interrupt_all(bool return_immediately = false); + * 中断所有工人的工作. + * 中断点被设置在了单个工作流程执行完毕的地方, 确保数据被处理完毕. + * 参数为是否立即返回, 当为false时, 此函数会一直等待所有工作线程 + * 中断退出以后才返回, 否则一直阻塞等待 + * 3. inline int workers_count() const; + * 获取当前工作线程数量. + * 4. count_t add_workers(const count_t& n); + * 增加工作线程数量方法. 返回调整后的数量, 内置锁保护. + * 参数为要增加的工作线程数量。 + * 5. count_t sub_workers(const count_t& n, + * bool return_immediately = false); + * 减少工作线程数量方法. 返回调整后的数量, 内置锁保护. + * 参数一为将要减少工作线程的数量; + * 参数二为是否立即返回, 当为false 时, 此函数会一直等待要被中断 + * 工作线程中断退出以后才会返回, 否则一直阻塞等待。 + * 裁员会中断工作线程, 但会保证单个工作流程执行结束. + * *****由于开发进度要求,此方法尚未完全实现,留作遗留, + * 待下个开发版本实现. ****** + * 6. count_t reset_count(const count_t& n, + * bool return_immediately = false); + * 调整工作线程数量方法,返回调整后的数量,内置锁保护。 + * 参数一为要将工作线程的数量调整后的值; + * 参数二为是否立即返回, 仅在当前工作线程的数量比参数一n大时才有效, + * 当为参数二的值为false 时, 此函数会一直等待多余工作线程中断退出 + * 以后才返回, 否则一直阻塞等待。 + * 裁员会中断工作线程, 但会保证单个工作流程执行结束. + * 此方法依赖上两个函数, ******故留作遗留.****** + * 7. 私有虚函数介绍: + * 1. 进入流程循环之前的处理函数 + * virtual void prepare(); + * 2. 一次工作流程 + * virtual void process(void) = 0; + * 3. 对于工作线程中断后的响应函数 + * virtual void interruption_respond(); + * 8. 其他 + * static void run(Workers& workers); [private] 线程执行函数 + * 4. 直接依赖: + * 1. boost 线程库、serialization单件等 + */ + + +/////////////////////////////// +// See examples logworkers.h // +/////////////////////////////// + + +#define BOOST_ALL_NO_LIB +#include +#include + +//using boost::serialization::singleton; +//using namespace boost; +template +class Workers : public boost::serialization::singleton { + public: + typedef unsigned int count_t; + typedef boost::mutex mutex_t; + public: + // 工人开工方法. + // 注意, 如果n小于或等于已有的工人数,则将不会创建新的工人. + void start(const count_t& n, bool return_immediately = false); + // 中断所有工人的工作. 中断点被设置在了单个工作流程执行完毕的地方 + void interrupt_all(bool return_immediately = false); + + // 工人数量 + inline int workers_count() const; + // 增加工人数量,返回调整后的数量 + count_t add_workers(const count_t& n); + + /* 以下两个方法留作遗留, 尚未完全实现 + // 裁员,返回裁员后的人数. + // 如果裁员必须保证工人的一个生产周期完成才可以裁掉 + count_t sub_workers(const count_t& n, bool return_immediately = false); + // 调整工人数量, 返回调整后的数量 + count_t reset_count(const count_t& n, bool return_immediately = false); + */ + Workers& operator=(const Workers&) = delete; + virtual ~Workers(); + private: + // 进入流程循环之前的处理函数 + virtual void prepare(); + // 一次工作流程 + virtual void process(void) = 0; + // 对于工作线程中断后的响应函数 + virtual void interruption_respond(); + // 线程函数 + static void run(Workers& workers); + private: + boost::thread_group workers; + // 因为 thread_group 内部维护的thread list对外不可见, + // 所以这里要再声明一个 thread list, 以便对每个工作线程进行管理. + // 裁员时凸显 thread list 的重要性. + // std::list threads; + mutex_t mu; // 调整工人数量时使用的锁 +}; + +#include +template +void Workers::start(const count_t& n, bool return_immediately/* = false*/) { + for (count_t i = workers_count(); i < n; ++i) { + //threads.push_back(workers.create(boost::bind(run, boost::ref(*this))))); + workers.create_thread(boost::bind(run, boost::ref(*this))); + } + if (! return_immediately) { + workers.join_all(); + } + else { + return; + } +} + +template +void Workers::interrupt_all(bool return_immediately/* = false*/) { + // interrupt all the working thread + workers.interrupt_all(); + if (! return_immediately) { + workers.join_all(); + } + else { + return; + } +} + +template +inline int Workers::workers_count() const { + return workers.size(); +} + + +template +void Workers::run(Workers& workers) +try { + // prepare, before loop + workers.prepare(); + //process loop + while (true) { + workers.process(); + // interruption point + boost::this_thread::interruption_point(); + } +} +catch (boost::thread_interrupted&) { + // interrupt exception handling + workers.interruption_respond(); +} + +#include +template +/*virtual*/void Workers::prepare() { + std::cout << "Now start a Workers thread(id:" + << boost::this_thread::get_id() + << ", RTTI:\"" << typeid(T).name() << "\")!" << std::endl; +} +template +/*virtual*/void Workers::interruption_respond() { + std::cout << "Workers thread(id:" << boost::this_thread::get_id() + << ", RTTI:\"" << typeid(T).name() + << "\") is interrupted." << std::endl; +} + +template +typename Workers::count_t Workers::add_workers(const count_t& n) { + mutex_t::scoped_lock lock(mu); + for (count_t i = 0; i < n; ++i) { + workers.add_thread(new boost::thread(run, boost::ref(*this))); + // 不会泄露,workers的析构会delete它 + // 参见 + // 中的thread_group::~thread_group() + /* + thread* new_woker = new thread(run, boost::ref(*this)); + workers.add_thread(new_worker); + threads.push_back(new_worker); + */ + } + return workers.size(); // 返回增加后的个数 +} + +/* 此方法未实现,在以后的开发版本中实现*/ +//template +//typename Workers::count_t Workers::sub_workers(const count_t& n) { +// mutex_t::scoped_lock lock(mu); +// for (count_t c = 0, auto it = threads.begin(); +// it != threads.end(); ++it) { +// // 从工人组里移除 +// workers.remove_thread(&(*it)); +// // 发出中断指令 +// it->interrupt(); +// // 断言此工作线程被要求中断 +// assert(it->interruption_requested()); +// // 从 threads list 中移除 +// threads.erase(it); +// // 遗留问题: +// // 此处内存有泄露,要选择在线程退出后再 delete it +// // 而且由于是在循环内部erase, 可能会多执行一次++it +// +// if (++c >= n) break; +// } +// return workers.size(); +//} + +/* 由于sub_workers()未实现,且此方法依赖sub_workers(), + * 所以此方法也未实现. 以后开发版本在实现 + */ +//template +//typename Workers::count_t Workers::reset_count(const count_t& n) {} + +template +Workers::~Workers() { + // interrupt all the working thread & wait + this->interrupt_all(/*false*/); +} + +#endif // WORKER_H +