#ifndef _THREADWORK_H_ #define _THREADWORK_H_ #pragma once struct cdata { struct impl; struct impl *_impl; volatile long _refcount; cdata(); void* __stdcall operator new(size_t size); void __stdcall operator delete(void *p); }; class iexcute { public: virtual cdata* doproc(cdata*) = 0; }; class istream :virtual public iexcute { public: virtual ~istream(){} }; class ifilter :virtual public iexcute { public: virtual ~ifilter(){} }; class ireport :virtual public iexcute { public: virtual ~ireport(){} }; class threadworker { public: class impl; threadworker(); ~threadworker(); void setup( int /*0>=: 使用win线程池减少执行时间,<-100:不使用任何线程,其他值:filter,report中的函数使用新线程*/ ); void apply(istream *[] ,ifilter*[] ,ireport*[] ); // 可以多次使用这个函数加入新的处理步骤。 void submit( long flag = 0/*使用win线程时,对filter(n:flag>>8),report(n:flag>>16)向线程池提交方式进行调整, 当队列有缓存并且缓存数量不大于n时提交任务, stream(flag&0x1)线程是否不以向线程池提交任务的方式使用*/ ); void submit(cdata * = nullptr); private: impl * _impl; }; #endif /*_THREADWORK_H_*/ //cpp file #include "threadworker.h" #include <windows.h> #include <stddef.h> #include <condition_variable> #include <mutex> #include <stdlib.h> #include <stdio.h> #include <assert.h> #include <thread> #include <future> #include <mutex> #include <queue> #include <atomic> #include <iostream> #define TRACE_PIPE printf #define TRACE_PIPE #define USE_MMPOOL /*内存函数:Copyright*/ /* The author of this software is David R.Hanson. Copyright(c) 1994, 1995, 1996, 1997 by David R.Hanson.All Rights Reserved. Permission to use, copy, modify, and distribute this software for any purpose, subject to the provisions described below, without fee is hereby granted, provided that this entire notice is included in all copies of any software that is or includes a copy or modification of this software and in all copies of the supporting documentation for such software. THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY.IN PARTICULAR, THE AUTHOR DOES MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. David Hanson / drh@microsoft.com / http://www.research.microsoft.com/~drh/ $Id: CPYRIGHT, v 1.2 1997 / 11 / 04 22 : 31 : 40 drh Exp $ */ /* */ #define THRESHOLD 400 #define hash(p, t) (((unsigned long)(p)>>3) & \ (sizeof (t)/sizeof ((t)[0])-1)) #define NDESCRIPTORS 512 #define NALLOC ((4096 + sizeof (union align) - 1)/ \ (sizeof (union align)))*(sizeof (union align)) class newmem { union align { #ifdef MAXALIGN char pad[MAXALIGN]; #else int i; long l; long *lp; void *p; void(*fp)(void); float f; double d; long double ld; #endif }; class newarena { struct arena { arena * prev; char * avail; char * limit; }; union header { struct arena b; union align a; }; arena * _arena; arena * _freechunks; int _nfree; public: newarena() :_arena(new arena()) { _arena->prev = nullptr; _arena->limit = _arena->avail = nullptr; } ~newarena() { free(); delete _arena; } void* alloc(long nbytes) { nbytes = ((nbytes + sizeof(union align) - 1) / (sizeof(union align)))*(sizeof(union align)); while (nbytes > _arena->limit - _arena->avail) { arena* ptr; char *limit; if ((ptr = _freechunks) != NULL) { _freechunks = _freechunks->prev; _nfree--; limit = ptr->limit; } else { long m = sizeof(union header) + nbytes + 10 * 1024; ptr = reinterpret_cast<arena*> (malloc(m)); limit = (char *)ptr + m; } *ptr = *_arena; _arena->avail = (char *)((union header *)ptr + 1); _arena->limit = limit; _arena->prev = ptr; } _arena->avail += nbytes; return _arena->avail - nbytes; } void free() { while (_arena->prev) { struct arena tmp = *_arena->prev; if (_nfree < THRESHOLD) { _arena->prev->prev = _freechunks; _freechunks = _arena->prev; _nfree++; _freechunks->limit = _arena->limit; } else delete _arena->prev; *_arena = tmp; } assert(_arena->limit == NULL); assert(_arena->avail == NULL); } }_arena; struct descriptor { struct descriptor *free; struct descriptor *link; const void *ptr; long size; const char *file; int line; } *htab[2048]; struct descriptor freelist = { &freelist }; struct descriptor *avail; int nleft; std::mutex _mutex; void *resize(void *ptr, long nbytes) { struct descriptor *bp = 0; void *newptr; assert(ptr); assert(nbytes > 0); #ifdef MAXALIGN if ((((unsigned long)ptr) &~(MAXALIGN - 1)) != 0 #else if (((unsigned long)ptr) % (sizeof(union align)) != 0 #endif || (bp = find(ptr)) == NULL || bp->free) throw std::exception("Allocation Failed"); newptr = alloc(nbytes); memcpy(newptr, ptr, nbytes < bp->size ? nbytes : bp->size); free(ptr); return newptr; } void *calloc(long count, long nbytes) { void *ptr; assert(count > 0); assert(nbytes > 0); ptr = alloc(count*nbytes); memset(ptr, '\0', count*nbytes); return ptr; } struct descriptor *dalloc(void *ptr, long size) { if (nleft <= 0) { avail = (struct descriptor *)_arena.alloc(NDESCRIPTORS * sizeof(*avail)); if (avail == NULL) return NULL; nleft = NDESCRIPTORS; } avail->ptr = ptr; avail->size = size; avail->free = avail->link = NULL; nleft--; return avail++; } descriptor *find(const void *ptr) { struct descriptor *bp = htab[hash(ptr, htab)]; while (bp && bp->ptr != ptr) bp = bp->link; return bp; } newmem() :avail(nullptr), nleft(0) {} public: static newmem& get() { static newmem _newmem; return _newmem; } void* alloc(long nbytes) { std::lock_guard<std::mutex> guard(_mutex); struct descriptor *bp = 0; void *ptr; assert(nbytes > 0); #ifdef MAXALIGN nbytes = (nbytes + MAXALIGN - 1) & ~(MAXALIGN - 1); #else nbytes = ((nbytes + sizeof(union align) - 1) / (sizeof(union align)))*(sizeof(union align)); #endif for (bp = freelist.free; bp; bp = bp->free) { if (bp->size > nbytes) { bp->size -= nbytes; ptr = (char *)bp->ptr + bp->size; if ((bp = dalloc(ptr, nbytes)) != NULL) { unsigned h = hash(ptr, htab); bp->link = htab[h]; htab[h] = bp; return ptr; } else { throw std::exception("Allocation Failed"); } } if (bp == &freelist) { struct descriptor *newptr = 0; if ((ptr = _arena.alloc(nbytes + NALLOC)) == NULL || (newptr = dalloc(ptr, nbytes + NALLOC)) == NULL) { throw std::exception("Allocation Failed"); } newptr->free = freelist.free; freelist.free = newptr; } } assert(0); return NULL; } void free(void *ptr) { if (ptr) { struct descriptor *bp = 0; if (((unsigned long)ptr) % (sizeof(union align)) != 0 || (bp = find(ptr)) == NULL || bp->free) throw std::exception("Allocation Failed"); bp->free = freelist.free; freelist.free = bp; } } }; struct cdata::impl { std::atomic_long _refcount; impl() { std::atomic_init(&_refcount, 0); } }; cdata::cdata() :_refcount(1), _impl(new cdata::impl()){} void* __stdcall cdata::operator new(size_t size) { #ifdef USE_MMPOOL return newmem::get().alloc(size); #else return malloc(size); #endif } void __stdcall cdata::operator delete(void *p) { #ifdef USE_MMPOOL newmem::get().free(p); #else free(p); #endif } class singlylist { typedef struct { SLIST_ENTRY entry; cdata* data; void* __stdcall operator new(size_t size) { assert(sizeof(singlylist::_titem) == size); return _aligned_malloc(size, MEMORY_ALLOCATION_ALIGNMENT); } void __stdcall operator delete(void *p) { _aligned_free(p); } }_titem, *_ptitem; PSLIST_HEADER plist; public: long count(){ return QueryDepthSList(plist); } cdata* lockedput (cdata* data){ _ptitem pitem = new _titem(); assert(pitem); pitem->data = data; PSLIST_ENTRY entry = InterlockedPushEntrySList(plist, &pitem->entry); pitem = reinterpret_cast<_ptitem>(entry); return pitem ?pitem->data:nullptr; } cdata* lockedget(){ PSLIST_ENTRY entry = InterlockedPopEntrySList(plist); _ptitem pitem = reinterpret_cast<_ptitem>(entry); if (pitem) { cdata* data = pitem->data; delete pitem; return data; } else return nullptr; } singlylist(){ plist = (PSLIST_HEADER)_aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT); assert(plist); InitializeSListHead(plist); } ~singlylist(){ InterlockedFlushSList(plist); _aligned_free(plist); } }; class linkptr { void * _list; int _offset; public: linkptr(int offset) :_list(nullptr), _offset(offset){} void push(void* p) { *pptr(p) = _list; _list = p; } void pop(void* p) { _list = *pptr(p); } void* get() { return _list; } void* next(void *p){return *pptr(p); } void** pptr(void* p) const { return (void**)((char*)(p) + _offset); } }; template<class T> class linktype : private linkptr { public: linktype(int offset = 0) : linkptr(offset){} void push(T* p) { linkptr::push(p); } T* next(T* p) { return (T*)(linkptr::next(p)); } T* get() { return (T*)(linkptr::get()); } void pop(T* p) { return linkptr::pop((T*)p); } operator T*() { return (T*)(linkptr::get()); } }; template<class T> class list { T* _current; public: list() :_current(nullptr){} void push(T* p) { p->rest = _current; _current = p; } T* next(T* p) { return p->rest; } void pop(T *p) { _current = p->rest; } operator T*() { return _current; } }; class threadworker::impl { public: virtual ~impl() { } virtual void apply(istream* stream[], ifilter* filter[], ireport* report[]) { } virtual void start(long flag) { } virtual void start(cdata* d) { } }; namespace submit { #ifdef __cplusplus #define $(T) _##T #else #define $(T) T #endif #define NEXTPTR(p,_,q) do{ p##->##_= q; }while(0) #define LINKPTR(p,_,q) do{ p##->##_= q; q = p; }while(0) #define T SubmitThread_T typedef struct $(SubmitThread_T) *T; typedef struct cdata *data; typedef struct $(pump) *pump; typedef void* vptr; typedef data(*vfun)(data, vptr); struct $(pump) { pump _rest; pump _next; struct t { struct t * _next; vfun*_pfun; vptr _vptr; }*_vfun; long _flag; const char* _name; }; class lockedlist { std::condition_variable cv; std::mutex mt; std::queue<data> queue; public: void put(data d) { std::lock_guard<std::mutex> l(mt); queue.push(d); cv.notify_one(); } data get(void) { std::unique_lock<std::mutex> l(mt); cv.wait(l, [this] {return !queue.empty(); }); data d = queue.front(); queue.pop(); return d; } }; class submitnode { submitnode *_root, *_rest, *_next; public: const char *_name; submitnode() :_root(nullptr), _rest(nullptr), _next(nullptr), _name("node") {} virtual ~submitnode() { free(_rest); } void free(submitnode * next) { for (auto * t = next; t; ) { auto* d = t; t = t->_next; delete d; } } void rest(submitnode * rest) { LINKPTR(rest, _next, _rest); rest->_root = this; } void root(submitnode * root) { _root = root; } void next(submitnode * next) { _next = next; } virtual void done(data d) { assert(_root); _root->done(d); } virtual void pump(data d) { return _next ? _next->pipe(d) : _root ? _root->pump(d):__nop(); } virtual void tick(data d) { for (auto * t = _rest; t; t = t->_next) t->tick(d); } virtual data todo(data d) { for (auto * t = _rest; t; t = t->_next) d = t->todo(d); return d; } virtual data pipe(data d){ submitnode::tick(d); return submitnode::todo(d); } }; class submitunit : public submitnode{ vfun _vfun; vptr _vptr; public: submitunit(vfun fun, vptr ptr) :_vfun(fun), _vptr(ptr) { _name = ("unit");} virtual data todo(data d) { return _vfun(d, _vptr); } }; class submitwork : public submitnode{ protected: virtual ~submitwork() {} virtual data work(data d) { d = pipe(d); done(d); return d; } virtual data todo(data d) { return work(d); } public: submitwork() { _name = "work"; } void applyf(vfun fun, vptr ptr) { rest(new submitunit(fun, ptr)); } }; class submitmain : public submitwork{ std::future<void> _fature; lockedlist &_list; virtual void main() { for (data d; work(d = _list.get());) ; } static void __stdcall submit(submitmain* _thisptr) { _thisptr->main(); } public: submitmain(lockedlist& l) :_list(l), _fature(std::async(&submitmain::submit, this)) { } ~submitmain() { _fature.get(); } }; class submittodo : public submitnode{ submitnode * _node; private: void node(submitnode * node) { node->next(_node); _node = node; _node->root(this); } void done(data d) { submitnode::pump(d); } virtual void pump(data d) { _node->todo(d); } virtual data todo(data d) { pump(d); return d; } virtual submitwork * getsubmit() { return new submitwork(); } public: submittodo() :_node(nullptr) { _name = "todo"; } virtual ~submittodo() { free(_node); } virtual void applyf(vfun* fun, vptr ptr) { for (submitwork * m; *fun; ++fun) { m = getsubmit(); m->applyf(*fun, ptr); node(m); } } }; class submitcont : public submittodo{ virtual data todo(data d) { return submitnode::todo(d); } }; class submititem : public submittodo { lockedlist _list; virtual void tick(data d) { if (!d || ++d->_impl->_refcount > 0) { return; } assert(0); } virtual void done(data d) { if (!d || --d->_impl->_refcount <= 0){ return submitnode::pump(d); } } virtual data todo(data d) { _list.put(d); return d; } private: virtual submitwork * getsubmit() { return new submitmain(_list); } }; class produceobj{ int _number_hardware; int _number_id; produceobj() :_number_hardware(std::thread::hardware_concurrency()), _number_id(0){ } public: static produceobj& factory() { static produceobj _producer; return _producer; } void closethread() { _number_hardware = 0; } submittodo* newitem(bool only1) { return only1 ? 1 < ++_number_id && _number_id <= _number_hardware ? new submititem() : new submittodo() : new submitcont(); } }; struct $(SubmitThread_T) { submitnode* _link; submitnode* tonode(pump p) { if (p->_vfun) { submittodo * m = produceobj::factory().newitem(!p->_rest); auto * i = p->_vfun; do { m->applyf(i->_pfun, i->_vptr); //del auto * t = i; i = i->_next; delete t->_pfun; delete t; } while (i); p->_vfun = nullptr; return m; } else { return new submitnode(); } } submitnode* applyf(pump p) { submitnode * r = tonode(p); r->_name = p->_name; for (auto * i = p->_rest; i;) { r->rest(applyf(i)); //del auto * t = i; i = i->_next; delete t; } p->_rest = nullptr; return r; } public: $(SubmitThread_T)(int count) : _link(new submitnode[count]){ for(int i = 1 ; i < count; ++i) _link[i - 1].next(&_link[i]); } ~$(SubmitThread_T)() { delete [] _link; } void apply(pump p,int i) { _link[i].rest(applyf(p)); } void pipe(data d) { _link[0].pipe(d); } }; class impl : public threadworker::impl{ T _mgr; static data streamfun(data d, vptr p){ return ((istream*)p)->doproc(d); } static data filterfun(data d, vptr p) { return ((ifilter*)p)->doproc(d); } static data reportfun(data d, vptr p) { return ((ireport*)p)->doproc(d); } public: impl() { _mgr = new $(SubmitThread_T)(3); } ~impl() { delete _mgr; } void start(long) { _mgr->pipe(nullptr); } void start(data d) { _mgr->pipe(d); } void apply(istream* stream[], ifilter* filter[], ireport* report[]){ if (stream) { pump p = new $(pump)(); p = new $(pump)(); p->_rest = nullptr; p->_next = nullptr; p->_flag = 0L; p->_name = "stream"; for (; *stream; stream++) { istream* i = *stream; { $(pump)::t *f = new $(pump)::t; f->_pfun = new vfun[2]; f->_pfun[0] = streamfun; f->_pfun[1] = nullptr; f->_vptr = i; f->_next = p->_vfun; p->_vfun = f; } } _mgr->apply(p,0); } if (filter) { pump p = new $(pump)(); p = new $(pump)(); p->_rest = nullptr; p->_next = nullptr; p->_flag = 0L; p->_name = "filter"; for (; *filter; filter++) { ifilter* i = *filter; { $(pump)::t *f = new $(pump)::t; f->_pfun = new vfun[2]; f->_pfun[0] = filterfun; f->_pfun[1] = nullptr; f->_vptr = i; f->_next = p->_vfun; p->_vfun = f; } } _mgr->apply(p, 1); } if (report) { pump p = new $(pump)(); p = new $(pump)(); p->_rest = nullptr; p->_next = nullptr; p->_flag = 0L; p->_name = "report"; for (; *report; report++) { ireport* i = *report; { $(pump)::t *f = new $(pump)::t; f->_pfun = new vfun[2]; f->_pfun[0] = reportfun; f->_pfun[1] = nullptr; f->_vptr = i; f->_next = p->_vfun; p->_vfun = f; } } _mgr->apply(p, 2); } } }; #undef T } class submitimpl : public threadworker::impl { friend class threadworker; long _refcount; HANDLE _exitevent; class idatapipe { protected: idatapipe * _datapipe; long _flag; public: virtual void pipe(cdata * d) { delete d; } virtual void setp(idatapipe * pipe) { _datapipe = pipe; } virtual idatapipe * getp() { return _datapipe; }; void setflag(long flag) {_flag = flag;} }; template <typename T> class worksubmit : public idatapipe { public: worksubmit * next; protected: struct node { node* rest; T* t; node(T* d) :t(d) {} }; list<node> _nodelist; PTP_WORK _tpwk; virtual const char* name(){ return ""; } public: worksubmit() { _tpwk = CreateThreadpoolWork(main, this, NULL); } ~worksubmit() { CloseThreadpoolWork(_tpwk); } virtual void push(T *t) { _nodelist.push(new node(t)); } virtual void pipe(cdata * d) { } static void __stdcall main(PTP_CALLBACK_INSTANCE instance, PVOID vptr, PTP_WORK tpwk) { ((worksubmit*)vptr)->run(instance, tpwk); } virtual void run(PTP_CALLBACK_INSTANCE , PTP_WORK ) = 0; }; class mainstream : public idatapipe { class workstream : public worksubmit<istream> { virtual const char* name() { return "name:stream"; } virtual void run(PTP_CALLBACK_INSTANCE instance, PTP_WORK tpwk) { assert(tpwk == _tpwk); long flag = _flag & 0xFF; if(flag & 1) CallbackMayRunLong(instance); _forever: for (node* n = _nodelist; n ; n = _nodelist.next(n)){ if (cdata * d = n->t->doproc(_locklist.lockedget())) TRACE_PIPE("stream doproc \n"), _datapipe->pipe(d); else return (void)TRACE_PIPE("stream exit \n"); } if (flag & 1) goto _forever; else SubmitThreadpoolWork(tpwk); } singlylist &_locklist; public: workstream(singlylist & sl) : _locklist(sl){} void start(){ SubmitThreadpoolWork(_tpwk);; } }; linktype<workstream> _workstream; singlylist _locklist; long _refcount; public: mainstream() : _workstream(offsetof(workstream, next)), _refcount(0){ } virtual idatapipe * getp(){ return this; }; void pipe(cdata * d) { assert(_refcount); if (InterlockedDecrement(&d->_refcount) == 0) { InterlockedExchange(&d->_refcount, 1); _locklist.lockedput(d); } } void push(istream* streams[]) { ++_refcount; workstream * ws = new workstream(_locklist); ws->setp(_datapipe); while (*streams) ws->push(*streams++); _workstream.push(ws); } void start() { for (workstream* n = _workstream; n; n = _workstream.next(n)) n->start(); } void setflag(long flag) { for (workstream* n = _workstream; n; n = _workstream.next(n)) n->setflag(flag); } }_twkstream; class mainfilter : public idatapipe { class parallel : public idatapipe { public: parallel * next; private: class workfilter : public worksubmit<ifilter> { virtual const char* name() { return "name:filter"; } virtual void run(PTP_CALLBACK_INSTANCE instance, PTP_WORK tpwk) { assert(tpwk == _tpwk); while (cdata * d = _locklist.lockedget()) { for (node* n = _nodelist; n; n = _nodelist.next(n)) d = n->t->doproc(d) ; if (d) TRACE_PIPE("filter doproc \n"), _datapipe->pipe(d); } } singlylist _locklist; public: workfilter() {} virtual idatapipe * getp() { return this; } virtual void pipe(cdata * d) { switch (_flag) { case 0: if (nullptr == _locklist.lockedput(d)) SubmitThreadpoolWork(_tpwk); break; default: { long count = _locklist.count(); _locklist.lockedput(d); if (0 < count && count <= _flag) SubmitThreadpoolWork(_tpwk); } break; } } }; public: parallel() : _parallel(offsetof(workfilter, next)),_refcount(0){} void setflag(long flag) { for (workfilter* n = _parallel; n; n = _parallel.next(n)) n->setflag(flag); } void push(ifilter *t) { ++_refcount; workfilter * wf = new workfilter(); wf->push(t); _parallel.push(wf); } virtual idatapipe * getp() { return this; } virtual void setp(idatapipe * pipe) { idatapipe::setp(pipe); for (workfilter* n = _parallel; n; n = _parallel.next(n)) n->setp(pipe); } virtual void pipe(cdata * d) { if (!_refcount) _datapipe->pipe(d); else if (InterlockedDecrement(&d->_refcount) == 0) { InterlockedExchange(&d->_refcount, _refcount); for (workfilter* n = _parallel; n; n = _parallel.next(n)) n->pipe(d); } } private: linktype<workfilter> _parallel; long _refcount; }_twkfilter; linktype<parallel> _workfilter; long _refcount; public: mainfilter():_workfilter(offsetof(parallel, next)), _refcount(0) { _workfilter.push(&_twkfilter); } void setflag(long flag) { for (parallel* n = _workfilter; n; n = _workfilter.next(n)) n->setflag((flag>>8) & 0xFF); } virtual idatapipe * getp() { return _twkfilter.getp(); }; virtual void setp(idatapipe * pipe) { idatapipe::setp(pipe); _workfilter.get()->setp(_datapipe); } void push(ifilter* filters[]) { if (++_refcount > 1) { parallel * wf = new parallel(); _workfilter.get()->setp(wf); _workfilter.push(wf); } while (*filters) _workfilter.get()->push(*filters++); _workfilter.get()->setp(_datapipe); } }_twkfilter; class mainreport : public idatapipe { class workreport : public worksubmit<ireport> { virtual const char* name() { return "name:report"; } virtual void run(PTP_CALLBACK_INSTANCE instance, PTP_WORK tpwk){ assert(tpwk == _tpwk); while (cdata * d = _locklist.lockedget()) { for (node* n = _nodelist; n; n = _nodelist.next(n)) d = n->t->doproc(d) ; if (d) TRACE_PIPE("report doproc \n"), _datapipe->pipe(d); } } singlylist _locklist; public: workreport(){} virtual void pipe(cdata * d) { switch (_flag) { case 0: if (nullptr == _locklist.lockedput(d)) SubmitThreadpoolWork(_tpwk); break; default: { long count = _locklist.count(); _locklist.lockedput(d); if(0 < count && count <= _flag) SubmitThreadpoolWork(_tpwk); } break; } } }; linktype<workreport> _workreport; singlylist _locklist; long _refcount; public: mainreport() : _workreport(offsetof(workreport, next)), _refcount(0) { } void setflag(long flag) { for (workreport* n = _workreport; n; n = _workreport.next(n)) n->setflag((flag>>16) & 0xFF); } virtual idatapipe * getp() { return this; }; void pipe(cdata * d) { if (!_refcount) _datapipe->pipe(d); else if (InterlockedDecrement(&d->_refcount) == 0) { InterlockedExchange(&d->_refcount, _refcount); for (workreport* n = _workreport; n; n = _workreport.next(n)) n->pipe(d); } } void push(ireport* reports[]) { ++_refcount; workreport * wr = new workreport(); wr->setp(_datapipe); while (*reports) wr->push(*reports++); _workreport.push(wr); } }_twkreport; submitimpl() : _twkstream() , _twkfilter() , _twkreport() { _twkstream.setp(_twkfilter.getp()); _twkfilter.setp(_twkreport.getp()); _twkreport.setp(_twkstream.getp()); } void apply(istream* stream[], ifilter* filter[], ireport* report[]) { if (report) _twkreport.push(report); if (filter) _twkfilter.push(filter); if (stream) _twkstream.push(stream); } void start(long flag) { _twkreport.setflag(flag); _twkfilter.setflag(flag); _twkstream.setflag(flag); _twkstream.start(); } }; threadworker::threadworker() : _impl (nullptr) { } void threadworker::setup(int i) { _impl = i < 0 ? (threadworker::impl*)new submit::impl() : (threadworker::impl*)new submitimpl(); if (i < -100) { submit::produceobj::factory().closethread(); } } threadworker::~threadworker() { delete _impl; } void threadworker::apply(istream* stream[], ifilter* filter[], ireport* report[]) { _impl->apply(stream, filter, report); } void threadworker::submit(long flag) { _impl->start(flag); } void threadworker::submit(cdata * d) { _impl->start(d); }