// external functions
// I placed it here, just because I don't want to include those many header files. : (
void lib_protected_init(void);
#define THREADTABLE_SIZE 1024 //最大的线程数目
#define MAX_WAIT_TIME_LENGTH 5*1000 //最长等待时间为5s
struct threadinfo //线程信息结构体
{
#ifndef WIN32
pthread_t self; //线程本身
#else
long self;
#endif
const char *name; //线程名字
CThread::thread_func_t *func; //成员函数指针
long number; //线程序号
#ifndef WIN32
int wakefd_recv; //接收句柄
int wakefd_send; //发送句柄
pthread_cond_t exiting; //线程信号量
#else
HANDLE wake_handle; //事件句柄
HANDLE exiting; //事件句柄
#endif
};
struct new_thread_args //新的线程数据参数结构体
{
CThread::thread_func_t *func; //成员函数指针
void *arg; //线程参数
struct threadinfo *ti; ////线程信息结构体
};
static struct threadinfo *threadtable[THREADTABLE_SIZE]; //建立一个线程信息结构体指针数组threadtable
#define THREAD(t) (threadtable[(t) % THREADTABLE_SIZE]) //
static long active_threads = 0; //当前活跃的线程数量
static long started_threads = 0; //已经创建开始的线程数
static long next_threadnumber; //下一个可用的要创建的线程序号
static struct threadinfo mainthread; // //主线程信息结构体
static int iInitilizated = 0; //初始化为0
#ifndef WIN32
pthread_key_t tsd_key; //线程键key
static pthread_mutex_t *threadtable_lock = NULL; //线程mutex锁
#else
static CRITICAL_SECTION *threadtable_lock = NULL; //线程CRITICAL临界区
#endif
static void lock(void) //这是该类主要的上锁函数
{
#ifndef WIN32
int ret;
if (!threadtable_lock)
return;
ret = pthread_mutex_lock(threadtable_lock); //mutex线程上锁
if (ret != 0)
{
error(ret, "ssthread-pthread: could not lock thread table:%s", strerror(errno));
//panic(ret, "thread-pthread: could not lock thread table");
}
#else
if (!threadtable_lock)
return;
EnterCriticalSection(threadtable_lock); //线程上锁CriticalSection
#endif
}
static void unlock(void) { //这是该类主要的上锁函数
#ifndef WIN32
int ret;
if (!threadtable_lock)
return;
ret = pthread_mutex_unlock(threadtable_lock); //线程解锁mutex
if (ret != 0)
{
error(ret, "thread-pthread: could not unlock thread table:%s", strerror(errno));
//panic(ret, "thread-pthread: could not unlock thread table");
}
#else
if (threadtable_lock)
LeaveCriticalSection(threadtable_lock); //线程解锁CriticalSection
return;
#endif
}
static void flushpipe(int fd) { //清空pipe管道,fd为管道句柄
unsigned char buf[128];
size_t bytes;
do {
#ifndef WIN32
bytes = read(fd, buf, sizeof(buf)); //将管道pipe句柄中的数据全部清空
#else
bytes = _read(fd, buf, sizeof(buf));
#endif
} while (bytes > 0);
}
// I copy it from socket.cpp
static int socket_set_blocking(int fd, int blocking) //将socket句柄设置为阻塞,非阻塞
{
#ifndef WIN32
int flags, newflags;
flags = fcntl(fd, F_GETFL); //设置类型
if (flags < 0) {
error(errno, "cannot get flags for fd %d", fd);
return -1;
}
if (blocking) //如果是阻塞模式
newflags = flags & ~O_NONBLOCK;
else
newflags = flags | O_NONBLOCK;
if (newflags != flags) {
if (fcntl(fd, F_SETFL, newflags) < 0) {
error(errno, "cannot set flags for fd %d", fd);
return -1;
}
}
return 0;
#else
return -1;
#endif
}
#ifndef WIN32
static long fill_threadinfo(pthread_t id, const char *name,
thread_func_t *func,
#else
static long fill_threadinfo(long id, const char *name,
CThread::thread_func_t *func,
#endif
struct threadinfo *ti) {
#ifndef WIN32
int pipefds[2]; //两个管道句柄
int ret = 0;
#endif
long first_try;
c_assert(active_threads < THREADTABLE_SIZE); //确保当前活跃的线程数量 小于 线程信息数组的线程数量
ti->self = id; //填充线程信息id
ti->name = name; //填充线程名字
ti->func = func; //填充线程函数指针
#ifndef WIN32
if (pipe(pipefds) < 0) //为该线程分配两个管道句柄
{
error(ret, "cannot allocate wakeup pipe for new thread:%s", strerror(errno));
//panic(errno, "cannot allocate wakeup pipe for new thread");
}
ti->wakefd_recv = pipefds[0]; //接收管道句柄
ti->wakefd_send = pipefds[1]; //发送管道句柄
socket_set_blocking(ti->wakefd_recv, 0); //为管道设置非阻塞模式
socket_set_blocking(ti->wakefd_send, 0);
ret = pthread_cond_init(&ti->exiting, NULL); //初始化信号量
if (ret != 0)
{
error(ret, "cannot create condition variable for new thread:%s", strerror(errno));
// panic(ret, "cannot create condition variable for new thread");
}
#else
ti->exiting = CreateEvent(NULL, TRUE, FALSE, NULL); //创建退出信号事件
ti->wake_handle = CreateEvent(NULL, TRUE, FALSE, NULL); //创建叫醒事件
if (ti->exiting == NULL)
{
error(0, "Cannot create new event handle: %s", strerror(errno));
//panic(0, "Cannot create new event handle.");
}
if (ti->wake_handle == NULL)
{
error(0, "Cannot create new event handle: %s", strerror(errno));
//panic(0, "Cannot create new event handle.");
}
#endif
first_try = next_threadnumber;
do {
ti->number = next_threadnumber++; //填充线程序号
if (ti->number == first_try + THREADTABLE_SIZE) //用来检测线程序号是否超过THREADTABLE_SIZE
{
error(0, "Cannot have more than %d active threads", THREADTABLE_SIZE);
}
} while (THREAD(ti->number) != NULL); //确保该线程号可用,之前无线程
THREAD(ti->number) = ti;
active_threads++; //总线程数+1
started_threads ++;
return ti->number;
}
static struct threadinfo *getthreadinfo(void) { //获取检查当前运行的线程的线程信息结构
struct threadinfo *threadinfo = NULL;
#ifndef WIN32
threadinfo = (struct threadinfo *)pthread_getspecific(tsd_key); //根据当前运行的线程,设置的线程键tsd_key获取
if (threadinfo == NULL)
{
error(0, "thread-pthread: pthread_getspecific failed: %s", strerror(errno));
} else
{
_assert(pthread_equal(threadinfo->self, pthread_self()));
}
#else
long iSelf = GetCurrentThreadId(); //当前线程句柄id
int i = 0;
for (i = 0;i < next_threadnumber; i++) //在当先开始和运行的线程中寻找对应的线程
{
if (THREAD(i) == NULL)
continue;
if (THREAD(i)->self == iSelf) //找到线程
break;
}
if (i == next_threadnumber||THREAD(i) == NULL)
threadinfo = NULL;
else
threadinfo = THREAD(i); //获得序号i的信息结构体
#endif
return threadinfo;
}
static void delete_threadinfo(void) {
struct threadinfo *threadinfo;
#ifdef WIN32
long lTempNumber = -1;
#endif
threadinfo = getthreadinfo(); //从线程信息数组中获取对应所需的信息结构体
if (!threadinfo)
return ;
#ifndef WIN32 //windows
pthread_cond_broadcast(&threadinfo->exiting); //利用退出信号量 广播该线程信息的退出删除 事件
pthread_cond_destroy(&threadinfo->exiting); //删除该线程信息结构体的退出信号事件
close(threadinfo->wakefd_recv); //关闭接收和发送管道句柄
close(threadinfo->wakefd_send);
THREAD(threadinfo->number) = NULL; //将该线程信息结构体在数组中的下标位置置为NULL 可用
#else //linux
SetEvent(threadinfo->exiting); //设置退出事件
CloseHandle(threadinfo->exiting); //关闭退出事件句柄
SetEvent(threadinfo->wake_handle); //激发叫醒事件
CloseHandle(threadinfo->wake_handle); //关闭叫醒事件句柄
lTempNumber = threadinfo->number;
#endif
active_threads--; //活跃线程数量减1
c_assert(threadinfo != &mainthread);
_free(threadinfo); //释放该线程结构体信息
#ifdef WIN32
THREAD(lTempNumber) = NULL; //将该线程信息结构体在数组中的下标位置置为NULL 可用
#endif
}
static void create_threadinfo_main(void) { //创建主线程结构体信息
int ret = 0;
#ifndef WIN32
fill_threadinfo(pthread_self(), "main", NULL, &mainthread); //填充主线程结构体信息
ret = pthread_setspecific(tsd_key, &mainthread); //制定主线程为线程键
if (ret != 0)
{
error(ret, "thread-pthread: pthread_getspecific failed: %s", strerror(errno));
}
#else
fill_threadinfo(GetCurrentThreadId(), "main", NULL, &mainthread); //填充主线程结构体信息
#endif
}
using namespace clib;
// Added by David, 2000-12-5.
void CThread::delete_threadinfo_main(void) { //删除主线程结构体信息
struct threadinfo *threadinfo;
threadinfo = getthreadinfo(); //根据设置的线程键获取 主线程的信息结构体
if (!threadinfo)
return;
#ifndef WIN32
pthread_cond_broadcast(&threadinfo->exiting); //利用退出信号量 广播主线程信息的退出删除 事件
pthread_cond_destroy(&threadinfo->exiting); //删除该线程信息结构体的退出信号事件
close(threadinfo->wakefd_recv); //关闭接收和发送管道句柄
close(threadinfo->wakefd_send);
#else
SetEvent(threadinfo->exiting); //设置退出事件
CloseHandle(threadinfo->exiting);
SetEvent(threadinfo->wake_handle);
CloseHandle(threadinfo->wake_handle);
#endif
THREAD(threadinfo->number) = NULL; //将该线程信息结构体在数组中的下标位置置为NULL 可用
active_threads--;
// _assert(threadinfo != &mainthread);
// _free(threadinfo);
}
// initilization function
void CThread::ThreadInit(void) //初始化该线程管理类
{
int ret = 0;
int i;
if (iInitilizated++) //确保初始化
return;
#ifndef WIN32
if (!threadtable_lock)
{
threadtable_lock = new pthread_mutex_t; //如果没锁,则为线程新建一个mutex信号锁threadtable_lock
if (!threadtable_lock)
return;
}
pthread_mutex_init(threadtable_lock, NULL); //初始化该信号锁threadtable_lock
#else
if (!threadtable_lock)
{
threadtable_lock = new CRITICAL_SECTION; //如果没锁,则为线程新建一个CRITICAL_SECTION信号锁threadtable_lock
if (!threadtable_lock)
return;
}
InitializeCriticalSection(threadtable_lock);
#endif
#ifndef WIN32
ret = pthread_key_create(&tsd_key, NULL); //创建初始化线程键tsd_key
if (ret != 0)
{
error(ret, "thread-pthread: pthread_key_create failed: %s", strerror(errno));
}
#else
//
#endif
for (i = 0; i < THREADTABLE_SIZE; i++) { //将线程信息结构体指针数组全部初始化为空NULL
threadtable[i] = NULL;
}
active_threads = 0;
create_threadinfo_main(); //创建主线程mainThread
// lib_protected_init();
}
void CThread::ThreadShutdown(void)
{
int ret = 0;
int running;
int i;
static int iShutdowned = 0;
if (--iInitilizated) //确保线程类被杀掉,重置初始
return;
c_assert(threadtable[0] != NULL);
lock();
running = 0;
for (i = 1; i < THREADTABLE_SIZE; i++) { //遍历线程信息结构体指针数组
if (threadtable[i] != NULL) {
debug("lib", 0, "Thread %ld (%s) still running",
threadtable[i]->number,
threadtable[i]->name);
running++; //确定该线程类中的线程数running
}
}
unlock();
if (running) //确保除了主线程外没有其他线程运行
return;
#ifndef WIN32
if (!threadtable_lock)
return;
ret = pthread_mutex_destroy(threadtable_lock); //杀掉线程数组的锁
if (ret != 0)
{
warning(ret, "cannot destroy threadtable lock");
}
SAFEDELETE(threadtable_lock);
#else
if (!threadtable_lock)
return;
DeleteCriticalSection(threadtable_lock);
SAFEDELETE(threadtable_lock);
#endif
//删除主线程信息结构体
// // I must delete main thread information in here, matched with create_threadinfo_main() inside of thread_init()
delete_threadinfo_main(); // It must be commented in here, because main thread
// information will be used in later.
}
#ifdef WIN32
static void * __stdcall new_thread(void *arg)
#else
static void *new_thread(void *arg)
#endif
{
int ret = 0;
struct new_thread_args *p = (struct new_thread_args *)arg; //arg强制转化为new_thread_args *类型
lock();
unlock();
#ifndef WIN32
ret = pthread_setspecific(tsd_key, p->ti); //将新创建的线程赋予线程键
if (ret != 0)
{
error(ret, "thread-pthread: pthread_setspecific failed: %s", strerror(errno));
}
#else
//
#endif
(p->func)(p->arg);
lock();
debug("lib.thread", 0, "Thread %ld (%s) terminates.",
p->ti->number, p->ti->name);
_free(p);
delete_threadinfo();
unlock();
return NULL;
}
long CThread::ThreadCreate(thread_func_t *func, void *arg){
return CThread::thread_create_real(func, "", arg);
}
long CThread::thread_create_real(thread_func_t *func, const char *name, void *arg)
{
long ret;
#ifndef WIN32
pthread_t id; //线程id
#else
long id = -1;
#endif
struct new_thread_args *p; //线程信息结构体参数
long number;
p = (struct new_thread_args *)_malloc(sizeof(*p)); //动态分配内存
p->func = func;
p->arg = arg;
p->ti = (struct threadinfo *)_malloc(sizeof(*(p->ti))); //动态分配内存
lock();
if (active_threads >= THREADTABLE_SIZE) { //确保线程结构体信息数组数量
unlock();
warning(0, "Too many threads, could not create new thread.");
_free(p);
return -1;
}
#ifndef WIN32
ret = pthread_create(&id, NULL, &new_thread, p); //以p为传入参数创建线程
if (ret != 0) {
unlock();
error(ret, "Could not create new thread.");
_free(p);
return -1;
}
#else //以p为传入参数创建线程
ret = _beginthreadex(NULL, 0, (unsigned int (__stdcall *)(void *))new_thread, p, 0, (unsigned *)&id);
// ret = _beginthreadex(NULL, 0, new_thread, p, 0, (unsigned *)&id);
if (ret <=0)
{
unlock();
error(ret, "Could not create new thread.");
_free(p);
return -1;
}
#endif
#ifndef WIN32
ret = pthread_detach(id);
if (ret != 0) {
warning(ret, "Could not detach new thread.");
}
#endif
number = fill_threadinfo(id, name, func, p->ti); //填充线程信息结构并保存在信息数组中
unlock();
return number;
}
// wait for single thread to exit, nTimeOut in millionseconds
void CThread::ThreadJoin(long thread, long nTimeOut)
{
struct threadinfo *threadinfo;
#ifndef WIN32
struct timespec abstime;
struct timeval now; //现在的时间
struct timezone zone;
#endif
int ret = 0;
if (thread < 0)
return;
lock();
threadinfo = THREAD(thread); //根据下标获得该线程信息结构体
if (threadinfo == NULL || threadinfo->number != thread) {
unlock();
return;
}
#ifndef WIN32
if (nTimeOut > 0)
{ //设定等待时间
gettimeofday(&now, &zone);
abstime.tv_sec = now.tv_sec + nTimeOut / 1000;
abstime.tv_nsec = now.tv_usec * 1000;
if (!threadtable_lock)
return;
//一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。
ret = pthread_cond_timedwait(&threadinfo->exiting, threadtable_lock, &abstime); //等待捕获退出信号量
if (ret == ETIMEDOUT)
{
if (threadinfo->name != NULL)
warning(0, "ThreadJoin: thread %s can't stop.", threadinfo->name);
} else
{
}
}
else // nTimeOut <= 0, wait infinitely!
{
if (!threadtable_lock)
return;
ret = pthread_cond_wait(&threadinfo->exiting, threadtable_lock); //等待捕获退出信号量
if (ret != 0)
{
warning(ret, "ThreadJoin: error in pthread_cond_wait");
}
}
unlock();
#else
if (nTimeOut <= 0)
nTimeOut = INFINITE;
unlock(); // Added here because of using WIN32
if (threadinfo->number != 0) // don't wait main thread
if (WaitForSingleObject(threadinfo->exiting, nTimeOut) == WAIT_TIMEOUT) //等待退出信号事件
{
if (threadinfo->name != NULL)
warning(0, "ThreadJoin: thread %s can't stop.", threadinfo->name);
}
// ResetEvent(threadinfo->exiting); // pointed by zxm, 2000-11-21
// unlock(); // Commented because of using WIN32
#endif
}
void CThread::ThreadJoinAll(long nTimeOut) {
long i;
long our_thread = ThreadSelf(); //当前运行的线程
for (i = 0; i < THREADTABLE_SIZE; ++i) {
if (THREAD(our_thread) != THREAD(i)) //如果不是当前运行的线程
ThreadJoin(i, nTimeOut); //就退出该线程
}
}
void CThread::ThreadWakeUpAll(void) {
long i;
long our_thread = ThreadSelf(); //当前运行的线程
for (i = 0; i < THREADTABLE_SIZE; ++i) {
if (THREAD(our_thread) != THREAD(i))
ThreadWakeUp(i); //唤醒所有当前不运行的线程
}
}
void CThread::ThreadJoinEvery(thread_func_t *func, long nTimeOut)
{
long i;
struct threadinfo *ti;
int ret = 0;
lock();
for (i = 0; i < THREADTABLE_SIZE; ++i) {
ti = THREAD(i);
if (ti == NULL || ti->func != func)
continue;
debug("lib.thread", 0,
"Waiting for %ld (%s) to terminate",
ti->number, ti->name);
#ifndef WIN32
if (!threadtable_lock)
return;
ret = pthread_cond_wait(&ti->exiting, threadtable_lock);
if (ret != 0) {
warning(ret, "ThreadJoin_all: error in "
"pthread_cond_wait");
}
#else
unlock();
WaitForSingleObject(ti->wake_handle, nTimeOut);
// ResetEvent(ti->wake_handle);
#endif
}
unlock();
}
long CThread::ThreadSelf(void) {
struct threadinfo *threadinfo = NULL;
#ifndef WIN32
threadinfo = (struct threadinfo *)pthread_getspecific(tsd_key); //获得当前运行的线程,根据线程键
#else
int i = 0;
long lCurrentThreadId = GetCurrentThreadId(); //获得当前运行线程的id
for (i = 0; i < THREADTABLE_SIZE; ++i)
{
if (THREAD(i))
if (lCurrentThreadId == THREAD(i)->self) //找到当前线程id所对应的线程信息结构体
return i;
}
#endif
if (threadinfo)
return threadinfo->number; //返回其序列号
else
return -1;
}
void CThread::ThreadWakeUp(long thread) {
struct threadinfo *threadinfo;
#ifndef WIN32
unsigned char c = 0;
int fd;
#endif
lock();
threadinfo = THREAD(thread); //根据下标获得对应线程信息结构体
if (threadinfo == NULL || threadinfo->number != thread) {
unlock();
return;
}
#ifndef WIN32
fd = threadinfo->wakefd_send; //发送管道
unlock();
write(fd, &c, 1); //发出运行信号
#else
unlock(); // Found by Zhang Yuan, 2001-2-19.
SetEvent(threadinfo->wake_handle); //设置唤醒事件
#endif
}
int CThread::thread_pollfd(int fd, int events, double timeout) {
#ifndef WIN32
struct pollfd pollfd[2];
struct threadinfo *threadinfo;
int milliseconds;
int ret;
threadinfo = getthreadinfo();
pollfd[0].fd = threadinfo->wakefd_recv;
pollfd[0].events = POLLIN;
pollfd[1].fd = fd;
pollfd[1].events = events;
milliseconds = (int)(timeout * 1000);
ret = poll(pollfd, 2, milliseconds);
if (ret < 0) {
if (errno != EINTR)
error(errno, "thread_pollfd: error in poll");
return -1;
}
if (pollfd[0].revents)
flushpipe(pollfd[0].fd);
return pollfd[1].revents;
#else
return -1;
#endif
}
int CThread::thread_poll(struct pollfd *fds, long numfds, double timeout) {
#ifndef WIN32
struct pollfd *pollfds;
struct threadinfo *threadinfo;
int milliseconds;
int ret;
threadinfo = getthreadinfo();
pollfds = (struct pollfd *)_malloc((numfds + 1) * sizeof(*pollfds));
pollfds[0].fd = threadinfo->wakefd_recv;
pollfds[0].events = POLLIN;
memcpy(pollfds + 1, fds, numfds * sizeof(*pollfds));
milliseconds = (int)(timeout * 1000);
ret = poll(pollfds, numfds + 1, milliseconds);
if (ret < 0) {
if (errno != EINTR)
error(errno, "thread_poll: error in poll");
return -1;
}
if (pollfds[0].revents)
flushpipe(pollfds[0].fd);
memcpy(fds, pollfds + 1, numfds * sizeof(*pollfds));
_free(pollfds);
return ret;
#else
return -1;
#endif
}
//void thread_sleep(double seconds) {
void CThread::ThreadSleep(long nMilliSeconds)
{
#ifndef WIN32
struct pollfd pollfd;
int ret;
#endif
struct threadinfo *threadinfo;
threadinfo = getthreadinfo();
if (!threadinfo)
{
error(0, "Can not get the current thread information:%s", strerror(errno));
return;
}
#ifndef WIN32
pollfd.fd = threadinfo->wakefd_recv;
pollfd.events = POLLIN;
#endif
#ifndef WIN32
ret = poll(&pollfd, 1, nMilliSeconds);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN) {
warning(errno, "thread_sleep: error in poll");
}
}
if (ret == 1) {
flushpipe(pollfd.fd);
}
#else
WaitForSingleObject(threadinfo->wake_handle, nMilliSeconds);
// ResetEvent(threadinfo->wake_handle);
#endif
}
#ifdef WIN32
#undef FUNC_NAME
#define FUNC_NAME(x) #x
int CThread::thread_fill_threadinfo(thread_func_t *func, long id)
{
struct threadinfo *ti = NULL;
long number = -1;
ti = (struct threadinfo *)_malloc(sizeof(*ti));
lock();
if (active_threads >= THREADTABLE_SIZE)
{
unlock();
warning(0, "Too many threads, could not create new thread.");
_free(ti);
return -1;
}
number = fill_threadinfo(id, FUNC_NAME(func), func, ti);
unlock();
return number;
}
int CThread::thread_delete_threadinfo(void)
{
struct threadinfo *threadinfo;
long lTempNumber = -1;
threadinfo = getthreadinfo();
SetEvent(threadinfo->exiting);
CloseHandle(threadinfo->exiting);
SetEvent(threadinfo->wake_handle);
CloseHandle(threadinfo->wake_handle);
lTempNumber = threadinfo->number;
active_threads--;
c_assert(threadinfo != &mainthread);
_free(threadinfo);
THREAD(lTempNumber) = NULL;
return 0;
}
#endif
long CThread::RunningThreadNumber(void)
{
return active_threads;
}
long CThread::StartedThreadNumber(void)
{
return started_threads;
}
char* CThread::GetThreadInfo(long &nSize)
{
static char tempBuffer[MAX_PATH];
char *p = NULL;
if (nSize < 0 || nSize >= THREADTABLE_SIZE)
return NULL;
if (THREAD(nSize))
{
p = strrchr(THREAD(nSize)->name, ':');
sprintf(tempBuffer, "%d:%s", THREAD(nSize)->self, p ? p + 1 : THREAD(nSize)->name);
}
else
return NULL;
nSize ++;
return tempBuffer;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CThread::CThread()
{
}
CThread::~CThread()
{
}