#ifndef __HLP_THREAD_POOL_H__
#define __HLP_THREAD_POOL_H__
#include <assert.h>
#include <list>
#include <pthread.h>
#include "winnix.h"
#include <iostream>
namespace hlp
{
class mlock
{
pthread_mutex_t mtx;
public:
mlock()
{
pthread_mutex_init(&mtx, NULL);
}
~mlock()
{
pthread_mutex_destroy(&mtx);
}
int lock()
{
return pthread_mutex_lock(&mtx);
}
void unlock()
{
pthread_mutex_unlock(&mtx);
}
operator pthread_mutex_t*()
{
return &mtx;
}
};
typedef bool (*pfncheck)(void* arg1, void* arg2);
class mlockex
{
public:
mlockex()
{
pthread_cond_init(&_cond, NULL);
}
~mlockex()
{
pthread_cond_destroy(&_cond);
}
void lock()
{
_lock.lock();
}
void unlock()
{
_lock.unlock();
}
int lock_wait(pfncheck fn, void* arg1, void* arg2, unsigned int mstmo = -1)
{
int retval = -1;
_lock.lock();
while ( fn( arg1, arg2 ) )
{
if ( mstmo == -1 )
{
pthread_cond_wait(&_cond, _lock);
retval = 0;
}
else
{
struct timespec abstime;
abstime.tv_sec = time(NULL) + mstmo/1000;
abstime.tv_nsec = (mstmo%1000)*1000000;
if ( ETIMEDOUT == pthread_cond_timedwait(&_cond, _lock, &abstime) )
retval = 1;
else
retval = 0;
break;
}
}
return retval;
}
void fire(bool all = false)
{
if ( all )
pthread_cond_broadcast(&_cond);
else
pthread_cond_signal(&_cond);
}
private:
mlock _lock;
pthread_cond_t _cond;
};
typedef void* (*pfntaskcb)(void* arg1, void* arg2);
class mthreadpool
{
public:
typedef enum _em_mthp_error_code
{
failed = -1,
ok = 0
}mthp_error_code;
static mthreadpool* create(unsigned int max, unsigned int min = 0, unsigned int inc = 1, unsigned int max_lock_time = -1, unsigned int max_idle_time = -1)
{
mthreadpool* mthp = new mthreadpool();
mthp->initialize(max, min, inc, max_lock_time, max_idle_time);
return mthp;
}
static void mthreadpool::destroy(mthreadpool* mthp)
{
mthp->stop();
}
private:
mthreadpool()
{
}
~mthreadpool()
{
}
class mtask_context
{
public:
mtask_context()
{
cb = NULL;
arg1 = arg2 = NULL;
}
void run()
{
if ( cb != NULL )
cb( arg1, arg2 );
}
pfntaskcb cb;
void* arg1;
void* arg2;
};
class mthread_context
{
public:
typedef enum _em_state_code{
idle,
busy
}state_code;
static bool none_task_callback_is_set(void* arg1, void* arg2)
{
pfntaskcb* cb = (pfntaskcb*)arg1;
bool* pstopped = (bool*)arg2;
return ((cb == NULL || *cb == NULL) && !(*pstopped));
}
static bool isbusy(void* arg1, void* arg2)
{
state_code* code = (state_code*)arg1;
return (*code == state_code::busy);
}
public:
mthread_context()
{
stopped = false;
mtask = new mtask_context();
update();
}
~mthread_context()
{
delete mtask;
}
bool is_busy()
{
bool isbusy = false;
_state_lock.lock();
isbusy = (state == state_code::busy);
_state_lock.unlock();
return isbusy;
}
int wait(unsigned int mstmo = -1)
{
int retval = _state_lock.lock_wait(isbusy, &state, NULL, mstmo);
_state_lock.unlock();
return retval;
}
void set_task(pfntaskcb cb, void* arg1, void* arg2, state_code _state)
{
mtask->cb = cb;
mtask->arg1 = arg1;
mtask->arg2 = arg2;
_state_lock.lock();
state = _state;
_state_lock.unlock();
}
void set(pfntaskcb cb, void* arg1, void* arg2, state_code _state)
{
_task_lock.lock();
set_task(cb, arg1, arg2, _state);
_task_lock.unlock();
dowork();
}
void dowork()
{
_task_lock.fire();
}
void done()
{
_state_lock.fire();
}
void set(mtask_context* t)
{
set(t->cb, t->arg1, t->arg2, state_code::busy);
}
mtask_context wait_for_task()
{
mtask_context mctx;
_task_lock.lock_wait(none_task_callback_is_set, &mtask->cb, &stopped);
mctx = *mtask;
_task_lock.unlock();
return mctx;
}
void update()
{
set(NULL, NULL, NULL, state_code::idle);
lastupdate = time(NULL);
}
void run()
{
mtask_context _task = wait_for_task();
_task.run();
done();
update();
}
public:
pthread_t tid;
mlockex _task_lock;
mlockex _state_lock;
mthreadpool* mpool;
time_t lastupdate;
state_code state;
bool stopped;
mtask_context* mtask;
};
static void* monitor_thread_proc(void* args)
{
pthread_detach(pthread_self());
mthreadpool* pthis = (mthreadpool*)args;
pthis->maintain_work_threads();
return NULL;
}
static void* dispatch_thread_proc(void* args)
{
pthread_detach(pthread_self());
mthreadpool* pthis = (mthreadpool*)args;
pthis->dispatch();
return NULL;
}
static void* mtask_thread_proc(void* args)
{
pthread_detach(pthread_self());
mthread_context* mthc = (mthread_context*)args;
while( !mthc->stopped )
{
mthc->run();
}
try
{
delete mthc;
}
catch(...)
{}
return NULL;
}
static bool none_task_to_do(void* arg1, void* arg2)
{
std::list<mtask_context*>* lmts = (std::list<mtask_context*>*)arg1;
return (*lmts).empty();
}
unsigned int initialize(unsigned int max, unsigned int min, unsigned int inc, unsigned int max_lock_time, unsigned int max_idle_time)
{
_used_thread_count = 0;
_stop = false;
init_work_threads(max, min, inc, max_lock_time, max_idle_time);
return mthp_error_code::ok;
}
unsigned int init_monitor_thread()
{
unsigned int retval = pthread_create(&_monitor_tid, 0, monitor_thread_proc, this);
if ( retval < 0 )
return mthp_error_code::failed;
return mthp_error_code::ok;
}
unsigned int init_dispatch_thread()
{
unsigned int retval = pthread_create(&_dispatch_tid, 0, dispatch_thread_proc, this);
if ( retval < 0 )
return mthp_error_code::failed;
return mthp_error_code::ok;
}
unsigned int init_work_threads(unsigned int max, unsigned int min, unsigned int inc, unsigned int max_lock_time, unsigned int max_idle_time)
{
if ( init_monitor_thread() != 0 || init_dispatch_thread() != 0 )
return mthp_error_code::failed;
auto_create_threads(min);
_max_thread_count = max;
_inc_thread_count = inc;
_max_lock_time = max_lock_time;
_max_idle_time = max_idle_time;
return mthp_error_code::ok;
}
unsigned int auto_create_threads(unsigned int count)
{
unsigned int retval = 0;
for ( unsigned int i = 0; i < count; i++ )
{
if ( 0 == create_thread_with_context() )
retval++;
}
return retval;
}
unsigned int create_thread_with_context()
{
unsigned int code = mthp_error_code::failed;
mthread_context* mthc = new mthread_context();
do
{
mthc->mpool = this;
unsigned int retval = pthread_create(&mthc->tid, 0, mtask_thread_proc, mthc);
if ( retval != 0 )
break;
_thread_contexts_lock.lock();
unsigned int count = _thread_contexts.size();
if ( count < _max_thread_count )
{
_thread_contexts.push_back(mthc);
code = mthp_error_code::ok;
}
_thread_contexts_lock.unlock();
} while (0);
if ( code != mthp_error_code::ok )
{
destroy_thread_with_context(mthc);
}
return code;
}
unsigned int destroy_thread_with_context(mthread_context* context)
{
context->stopped = true;
pthread_cancel(context->tid);
return mthp_error_code::ok;
}
unsigned int maintain_work_threads()
{
while( !_stop )
{
msleep(1000);
time_t now = time(NULL);
_thread_contexts_lock.lock();
std::list<mthread_context*>::iterator iter = _thread_contexts.begin();
for ( ; iter != _thread_contexts.end(); )
{
unsigned int lock_time = (unsigned int)(now - (*iter)->lastupdate);
if ( (_max_lock_time != -1 && lock_time > _max_lock_time && (*iter)->is_busy())
|| (_max_idle_time != -1 && lock_time > _max_idle_time) )
{
destroy_thread_with_context(*iter);
iter = _thread_contexts.erase(iter);
}
else
{
++iter;
}
}
_thread_contexts_lock.unlock();
}
return mthp_error_code::ok;
}
mthread_context* get()
{
mthread_context* mthc = NULL;
_thread_contexts_lock.lock();
std::list<mthread_context*>::iterator iter = _thread_contexts.begin();
for ( ; iter != _thread_contexts.end(); ++iter )
{
if ( !(*iter)->is_busy() )
{
mthc = *iter;
_thread_contexts.erase(iter);
break;
}
}
unsigned int allcnt = _thread_contexts.size()+_used_thread_count;
if ( mthc == NULL && allcnt < _max_thread_count )
{
unsigned int retval = 0;
for ( unsigned int i = 0; i < _inc_thread_count && (i+allcnt) < _max_thread_count; i++ )
{
mthread_context* mctx = new mthread_context();
mctx->mpool = this;
if ( 0 != pthread_create(&mctx->tid, 0, mtask_thread_proc, mctx) )
{
delete mctx;
continue;
}
if ( i == 0 )
{
mthc = mctx;
continue;
}
_thread_contexts.push_back(mctx);
}
}
if ( mthc != NULL )
++_used_thread_count;
_thread_contexts_lock.unlock();
return mthc;
}
void release(mthread_context* mthc)
{
if ( mthc == NULL )
return;
_thread_contexts_lock.lock();
_thread_contexts.push_back(mthc);
--_used_thread_count;
_thread_contexts_lock.unlock();
}
void dispatch()
{
while(true)
{
_tasks_lock.lock_wait(none_task_to_do, &_tasks, NULL);
mtask_context* t = _tasks.front();
_tasks.pop_front();
_tasks_lock.unlock();
mthread_context* mthc = get();
if ( mthc != NULL )
{
mthc->set(t);
release(mthc);
}
delete t;
}
}
void stop()
{
_stop = true;
_thread_contexts_lock.lock();
std::list<mthread_context*>::iterator iter = _thread_contexts.begin();
for ( ; iter != _thread_contexts.end(); ++iter)
{
destroy_thread_with_context(*iter);
}
_thread_contexts_lock.unlock();
pthread_join(_monitor_tid, NULL);
pthread_join(_dispatch_tid, NULL);
}
public:
unsigned int exec(pfntaskcb cb, void* arg1, void* arg2)
{
mtask_context* task = new mtask_context;
task->cb = cb;
task->arg1 = arg1;
task->arg2 = arg2;
_tasks_lock.lock();
_tasks.push_back(task);
_tasks_lock.unlock();
_tasks_lock.fire();
return mthp_error_code::ok;
}
unsigned int synexec(pfntaskcb cb, void* arg1, void* arg2, unsigned int tmo)
{
unsigned int retval = mthp_error_code::failed;
mthread_context* mthc = get();
if ( mthc != NULL )
{
mthc->set(cb, arg1, arg2, mthread_context::busy);
if ( 0 == mthc->wait(tmo) )
retval = mthp_error_code::ok;
release(mthc);
}
return retval;
}
private:
unsigned int _max_thread_count;
unsigned int _inc_thread_count;
unsigned int _max_lock_time;
unsigned int _max_idle_time;
unsigned int _used_thread_count;
pthread_t _monitor_tid;
pthread_t _dispatch_tid;
std::list<mthread_context*> _thread_contexts;
mlock _thread_contexts_lock;
std::list<mtask_context*> _tasks;
mlockex _tasks_lock;
bool _stop;
};
}
#endif // __HLP_THREAD_POOL_H__
简单的线程池
最新推荐文章于 2024-09-19 13:36:34 发布