1. 线程的定义

1.1 线程定义在scheduler.h文件中,其定义如下所示

/* Thread itself. */
typedef struct _thread {
unsigned long id; /*identify*/
unsigned char type; /* thread type */
struct _thread *next; /* next pointer of the thread */
struct _thread *prev; /* previous pointer of the thread */
struct _thread_master *master; /* pointer to the struct thread_master. */
int (*func) (struct _thread *); /* event function */
void *arg; /* event argument */
timeval_t sands; /* rest of time sands value. */
union {
int val; /* second argument of the event. */
int fd; /* file descriptor in case of read/write. */
struct {
pid_t pid; /* process id a child thread is wanting. */
int status; /* return status of the process */
} c;
} u;
} thread_t;

1.2. 线程链表定义

/* Linked list of thread. */
typedef struct _thread_list {
thread_t *head;
thread_t *tail;
int count;
} thread_list_t;

线程类型的定义如下:

/* Thread types. */
#define THREAD_READ 0 //读线程
#define THREAD_WRITE 1 //写线程
#define THREAD_TIMER 2 //计时器线程
#define THREAD_EVENT 3 //事件线程
#define THREAD_CHILD 4 //子线程
#define THREAD_READY 5 //就绪线程
#define THREAD_UNUSED 6 //未使用线程
#define THREAD_WRITE_TIMEOUT 7 //写超时线程
#define THREAD_READ_TIMEOUT 8 //读超时线程
#define THREAD_CHILD_TIMEOUT 9 //子超时线程
#define THREAD_TERMINATE 10 //停止线程
#define THREAD_READY_FD 11

1.3.主线程定义

/* Master of the theads. */
typedef struct _thread_master {
thread_list_t read;
thread_list_t write;
thread_list_t timer;
thread_list_t child;
thread_list_t event;
thread_list_t ready;
thread_list_t unuse;
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
unsigned long alloc;
} thread_master_t;

2. 线程操作

2.1 生成主线程

/* global vars */
thread_master_t *master = NULL; /* Make thread master. */
thread_master_t *
thread_make_master(void)
{
thread_master_t *new; new = (thread_master_t *) MALLOC(sizeof (thread_master_t));
return new;
}

2.2 销毁一个主线程

/* Stop thread scheduler. */
void
thread_destroy_master(thread_master_t * m)
{
thread_cleanup_master(m);
FREE(m);
} //调用子函数,清空主线程的内容
/* Cleanup master */
static void
thread_cleanup_master(thread_master_t * m)
{
/* Unuse current thread lists */
thread_destroy_list(m, m->read);
thread_destroy_list(m, m->write);
thread_destroy_list(m, m->timer);
thread_destroy_list(m, m->event);
thread_destroy_list(m, m->ready); /* Clear all FDs */
FD_ZERO(&m->readfd);
FD_ZERO(&m->writefd);
FD_ZERO(&m->exceptfd); /* Clean garbage */
thread_clean_unuse(m);
}
//回收主线程内存
FREE(m);

2.3 增加一个简单的事件线程

/* Add simple event thread. */
thread_t *
thread_add_terminate_event(thread_master_t * m)
{
thread_t *thread; assert(m != NULL); thread = thread_new(m);
thread->type = THREAD_TERMINATE;
thread->id = ;
thread->master = m;
thread->func = NULL;
thread->arg = NULL;
thread->u.val = ;
thread_list_add(&m->event, thread); return thread;
}

2.4 创建不同类型的线程,并加入主线程中的对应线程链表,如读线程为例介绍

/* Add new read thread. */
thread_t *
thread_add_read(thread_master_t * m, int (*func) (thread_t *)
, void *arg, int fd, long timer)
{
thread_t *thread; assert(m != NULL); if (FD_ISSET(fd, &m->readfd)) {
log_message(LOG_WARNING, "There is already read fd [%d]", fd);
return NULL;
} thread = thread_new(m);
thread->type = THREAD_READ;
thread->id = ;
thread->master = m;
thread->func = func;
thread->arg = arg;
FD_SET(fd, &m->readfd);
thread->u.fd = fd; /* Compute read timeout value */
set_time_now();
thread->sands = timer_add_long(time_now, timer); /* Sort the thread. */
thread_list_add_timeval(&m->read, thread); return thread;
}

2.4.1 创建一个新的线程

/* Make new thread. */
thread_t *
thread_new(thread_master_t * m)
{
thread_t *new; /* If one thread is already allocated return it */
if (m->unuse.head) {
new = thread_trim_head(&m->unuse);
memset(new, , sizeof (thread_t));
return new;
} new = (thread_t *) MALLOC(sizeof (thread_t));
m->alloc++;
return new;
}

2.4.2 设置为读线程

    thread->type = THREAD_READ;
thread->id = ;
thread->master = m;
thread->func = func;
thread->arg = arg;
FD_SET(fd, &m->readfd);
thread->u.fd = fd;

2.4.3 根据超时时间将读进程加入读进程列表中

/* Add a thread in the list sorted by timeval */
void
thread_list_add_timeval(thread_list_t * list, thread_t * thread)
{
thread_t *tt; for (tt = list->head; tt; tt = tt->next) {
if (timer_cmp(thread->sands, tt->sands) <= )
break;
} if (tt)
thread_list_add_before(list, tt, thread);
else
thread_list_add(list, thread);
}

2.5 取消线程,从对应类型的线程列表中去除该线程,将它设置为unused类型,并加入unused线程链表。

/* Cancel thread from scheduler. */
void
thread_cancel(thread_t * thread)
{
switch (thread->type) {
case THREAD_READ:
assert(FD_ISSET(thread->u.fd, &thread->master->readfd));
FD_CLR(thread->u.fd, &thread->master->readfd);
thread_list_delete(&thread->master->read, thread);
break;
case THREAD_WRITE:
assert(FD_ISSET(thread->u.fd, &thread->master->writefd));
FD_CLR(thread->u.fd, &thread->master->writefd);
thread_list_delete(&thread->master->write, thread);
break;
case THREAD_TIMER:
thread_list_delete(&thread->master->timer, thread);
break;
case THREAD_CHILD:
/* Does this need to kill the child, or is that the
* caller's job?
* This function is currently unused, so leave it for now.
*/
thread_list_delete(&thread->master->child, thread);
break;
case THREAD_EVENT:
thread_list_delete(&thread->master->event, thread);
break;
case THREAD_READY:
case THREAD_READY_FD:
thread_list_delete(&thread->master->ready, thread);
break;
default:
break;
} thread->type = THREAD_UNUSED;
thread_add_unuse(thread->master, thread);
}

2.6 获取下一个就绪进程

/* Fetch next ready thread. */
thread_t *
thread_fetch(thread_master_t * m, thread_t * fetch)
{
int ret, old_errno;
thread_t *thread;
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
timeval_t timer_wait;
int signal_fd;
#ifdef _WITH_SNMP_
timeval_t snmp_timer_wait;
int snmpblock = ;
int fdsetsize;
#endif assert(m != NULL); /* Timer initialization */
memset(&timer_wait, , sizeof (timeval_t)); retry: /* When thread can't fetch try to find next thread again. */ /* If there is event process it first. */
while ((thread = thread_trim_head(&m->event))) {
*fetch = *thread; /* If daemon hanging event is received return NULL pointer */
if (thread->type == THREAD_TERMINATE) {
thread->type = THREAD_UNUSED;
thread_add_unuse(m, thread);
return NULL;
}
thread->type = THREAD_UNUSED;
thread_add_unuse(m, thread);
return fetch;
} /* If there is ready threads process them */
while ((thread = thread_trim_head(&m->ready))) {
*fetch = *thread;
thread->type = THREAD_UNUSED;
thread_add_unuse(m, thread);
return fetch;
} /*
* Re-read the current time to get the maximum accuracy.
* Calculate select wait timer. Take care of timeouted fd.
*/
set_time_now();
thread_compute_timer(m, &timer_wait); /* Call select function. */
readfd = m->readfd;
writefd = m->writefd;
exceptfd = m->exceptfd; signal_fd = signal_rfd();
FD_SET(signal_fd, &readfd); #ifdef _WITH_SNMP_
/* When SNMP is enabled, we may have to select() on additional
* FD. snmp_select_info() will add them to `readfd'. The trick
* with this function is its last argument. We need to set it
* to 0 and we need to use the provided new timer only if it
* is still set to 0. */
fdsetsize = FD_SETSIZE;
snmpblock = ;
memcpy(&snmp_timer_wait, &timer_wait, sizeof(timeval_t));
snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
if (snmpblock == )
memcpy(&timer_wait, &snmp_timer_wait, sizeof(timeval_t));
#endif ret = select(FD_SETSIZE, &readfd, &writefd, &exceptfd, &timer_wait); /* we have to save errno here because the next syscalls will set it */
old_errno = errno; /* Handle SNMP stuff */
#ifdef _WITH_SNMP_
if (ret > )
snmp_read(&readfd);
else if (ret == )
snmp_timeout();
#endif /* handle signals synchronously, including child reaping */
if (FD_ISSET(signal_fd, &readfd))
signal_run_callback(); /* Update current time */
set_time_now(); if (ret < ) {
if (old_errno == EINTR)
goto retry;
/* Real error. */
DBG("select error: %s", strerror(old_errno));
assert();
} /* Timeout children */
thread = m->child.head;
while (thread) {
thread_t *t; t = thread;
thread = t->next; if (timer_cmp(time_now, t->sands) >= ) {
thread_list_delete(&m->child, t);
thread_list_add(&m->ready, t);
t->type = THREAD_CHILD_TIMEOUT;
}
} /* Read thead. */
thread = m->read.head;
while (thread) {
thread_t *t; t = thread;
thread = t->next; if (FD_ISSET(t->u.fd, &readfd)) {
assert(FD_ISSET(t->u.fd, &m->readfd));
FD_CLR(t->u.fd, &m->readfd);
thread_list_delete(&m->read, t);
thread_list_add(&m->ready, t);
t->type = THREAD_READY_FD;
} else {
if (timer_cmp(time_now, t->sands) >= ) {
FD_CLR(t->u.fd, &m->readfd);
thread_list_delete(&m->read, t);
thread_list_add(&m->ready, t);
t->type = THREAD_READ_TIMEOUT;
}
}
} /* Write thead. */
thread = m->write.head;
while (thread) {
thread_t *t; t = thread;
thread = t->next; if (FD_ISSET(t->u.fd, &writefd)) {
assert(FD_ISSET(t->u.fd, &writefd));
FD_CLR(t->u.fd, &m->writefd);
thread_list_delete(&m->write, t);
thread_list_add(&m->ready, t);
t->type = THREAD_READY_FD;
} else {
if (timer_cmp(time_now, t->sands) >= ) {
FD_CLR(t->u.fd, &m->writefd);
thread_list_delete(&m->write, t);
thread_list_add(&m->ready, t);
t->type = THREAD_WRITE_TIMEOUT;
}
}
}
/* Exception thead. */
/*... */ /* Timer update. */
thread = m->timer.head;
while (thread) {
thread_t *t; t = thread;
thread = t->next; if (timer_cmp(time_now, t->sands) >= ) {
thread_list_delete(&m->timer, t);
thread_list_add(&m->ready, t);
t->type = THREAD_READY;
}
} /* Return one event. */
thread = thread_trim_head(&m->ready); #ifdef _WITH_SNMP_
run_alarms();
netsnmp_check_outstanding_agent_requests();
#endif /* There is no ready thread. */
if (!thread)
goto retry; *fetch = *thread;
thread->type = THREAD_UNUSED;
thread_add_unuse(m, thread); return fetch;
}

2.7 子线程处理,便利子线程链表取出子线程,并放入就绪线程链表。

/* Synchronous signal handler to reap child processes */
void
thread_child_handler(void * v, int sig)
{
thread_master_t * m = v; /*
* This is O(n^2), but there will only be a few entries on
* this list.
*/
thread_t *thread;
pid_t pid;
int status = ;
while ((pid = waitpid(-, &status, WNOHANG))) {
if (pid == -) {
if (errno == ECHILD)
return;
DBG("waitpid error: %s", strerror(errno));
assert();
} else {
thread = m->child.head;
while (thread) {
thread_t *t;
t = thread;
thread = t->next;
if (pid == t->u.c.pid) {
thread_list_delete(&m->child, t);
thread_list_add(&m->ready, t);
t->u.c.status = status;
t->type = THREAD_READY;
break;
}
}
}
}
}

2.8 线程调用

/* Call thread ! */
void
thread_call(thread_t * thread)
{
thread->id = thread_get_id();
(*thread->func) (thread);
}

2.9 启动调度器

/* Our infinite scheduling loop */
void
launch_scheduler(void)
{
thread_t thread; signal_set(SIGCHLD, thread_child_handler, master); /*
* Processing the master thread queues,
* return and execute one ready thread.
*/
while (thread_fetch(master, &thread)) {
/* Run until error, used for debuging only */
#ifdef _DEBUG_
if ((debug & ) == ) {
debug &= ~;
thread_add_terminate_event(master);
}
#endif
thread_call(&thread);
}
}

深入学习keepalived之预备工作--线程的更多相关文章

  1. Golang源码学习:调度逻辑(三)工作线程的执行流程与调度循环

    本文内容主要分为三部分: main goroutine 的调度运行 非 main goroutine 的退出流程 工作线程的执行流程与调度循环. main goroutine 的调度运行 runtim ...

  2. Android(java)学习笔记267:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  3. Android(java)学习笔记211:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  4. delphi 线程教学第三节:设计一个有生命力的工作线程

    第三节:设计一个有生命力的工作线程   创建一个线程,用完即扔.相信很多初学者都曾这样使用过. 频繁创建释放线程,会浪费大量资源的,不科学.   1.如何让多线程能多次被复用?   关键是不让代码退出 ...

  5. 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理

    1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...

  6. JavaSE学习笔记(13)---线程池、Lambda表达式

    JavaSE学习笔记(13)---线程池.Lambda表达式 1.等待唤醒机制 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用 ...

  7. JavaSE学习笔记(12)---线程

    JavaSE学习笔记(12)---线程 多线程 并发与并行 并发:指两个或多个事件在同一个时间段内发生. 并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...

  8. Linux 系统编程 学习:11-线程:线程同步

    Linux 系统编程 学习:11-线程:线程同步 背景 上一讲 我们介绍了线程的属性 有关设置.这一讲我们来看线程之间是如何同步的. 额外安装有关的man手册: sudo apt-get instal ...

  9. 转:学习笔记: Delphi之线程类TThread

    学习笔记: Delphi之线程类TThread - 5207 - 博客园http://www.cnblogs.com/5207/p/4426074.html 新的公司接手的第一份工作就是一个多线程计算 ...

随机推荐

  1. [python]模块及包

    一 .module 通常模块为一个文件,直接使用import来导入就好了.可以作为module的文件类型有".py".".pyo".".pyc&quo ...

  2. .Net Core 项目部署IIS简单步骤

    1.新建一个解决方案: 我习惯会把运行文件移至一级目录 然后清除CoreTest 文件夹里面的文件 2.在解决方案中新建一个项目 点击确认有,这里有几种选择类型,我一般选择空类型(这里需要注意一下,空 ...

  3. React 使用browserHistory项目访问404问题

    最近项目里面用到了React但是发布到iis站点之后,路由地址 刷新访问直接404错误.查阅资料之后发现是iis缺少配置URL重写 的问题导致的.下面我们来图形化配置,简单的配置下IIS 打开IIS使 ...

  4. session的获取

    Springmvc: RequestAttributes ra = RequestContextHolder.getRequestAttributes(); HttpServletRequest re ...

  5. c++实验2 顺序存储线性表

    线性表顺序存储 实现了动态数组的增删改查  前驱后继  A=AUB 动态数组右移 (1)顺序表存储结构的定义(类的声明): class SeqList { protected: DataType *l ...

  6. React进阶篇(2) -- Redux

    前言 如果还不知道为什么要使用Redux,说明你暂时还不需要它. 三大原则 单一数据源 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一 ...

  7. linux下配置apache多站点访问-小案例

    一级域名(baidu.com)也叫作顶级域名,注册一级域名是需要付费的. 而二级域名(image.baidu.com)是一级域名的延伸,所以只要购买了一级域名,二级域名是可以任意配置的. 其实(www ...

  8. day--39-MySQL的多表查询

    多表查询一:表的基本介绍 可以参考:https://www.cnblogs.com/cdf-opensource-007/p/6517627.html 建立一个员工表信息表和一个部门表,每个员工都对应 ...

  9. C++_友元1-友元类是什么

    友元函数:不是类的成员函数,但是能够访问类的私有数据成员. 之前有个矛盾就是规定非成员函数不能直接访问类的私有数据,但是这会儿却可以,但那只是针对常规非成员函数而言,特殊的非成员函数就可以访问类的私有 ...

  10. python-repr()和val()函数

    1. repr() 函数将对象转化为供解释器读取的形式. 语法 以下是 repr() 方法的语法: repr(object) 参数 object -- 对象. 返回值 返回一个对象的 string 格 ...