概念介绍
线程-调度的基本单位
线程和进程的区别
- 进程是资源分配的基本单位
- 创建一个线程的资源成本小,工作效率高
- 线程是cpu或操作系统调度的基本单位
线程和进程共享的资源
- 同一块地址空间
- 文件描述符表
- 信号处理方式
- 当前工作目录
- 用户id和组id
线程独立的资源
- 栈空间
- 线程ID
- 一组寄存器的值
- errno变量
- 信号屏蔽字以及调度优先级
相关函数介绍
函数汇总:
函数 |
功能 |
线程的创建及退出 |
pthread_create |
创建线程 |
pthread_join |
等待线程终止 |
pthread_detach |
将线程变为detach状态 |
pthread_exit |
终止线程并返回终止状态 |
线程创建参数 |
phread_attr_init |
初始化attr参数 |
pthread_attr_destroy |
销毁attr参数 |
pthread_attr_setstack |
设置线程的栈地址和栈大小 |
pthread_attr_setstacksize |
设置线程的栈大小 |
pthread_attr_setdetachstate |
设置attr参数中的detach属性 |
pthread_attr_setinheritsched |
设置attr的继承调度策略 |
pthread_attr_setschedparam |
设置attr的调度参数 |
pthread_attr_setschedpolicy |
设置attr的调度策略 |
线程取消及相关属性 |
pthread_setcancelstate |
设置本线程是否允许被cancel |
pthread_setcanceltype |
设置本线程的取消类型 |
pthread_testcancel |
设置取消点 |
pthread_cancel |
取消线程 |
pthread_cleanup_push |
注册线程清理函数 |
pthread_cleanup_pop |
执行(撤销)线程清理函数 |
线程创建
pthread_create
1 2
| int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 功能:创建线程。
|
|
名称 |
说明 |
备注 |
参数 |
thread |
返回线程ID |
attr参数决定了创建的线程属性,由后续的phread_attr_init初始化,若填NULL则为默认属性 |
attr |
设置线程属性 |
start_routine |
线程处理函数 |
arg |
传递给线程函数的参数 |
返回值 |
int |
成功返回0,失败返回错误值 |
线程属性
phread_attr_init
1 2
| int pthread_attr_init(pthread_attr_t *attr); 功能:初始化attr参数
|
|
名称 |
说明 |
备注 |
参数 |
attr |
指定要初始化的参数 |
调用该函数对attr初始化后才可调用后续的函数来设置attr的属性值 |
返回值 |
int |
成功返回0,失败返回非0 |
pthread_attr_destroy
1 2
| int pthread_attr_destroy(pthread_attr_t *attr); 功能:销毁attr参数
|
|
名称 |
说明 |
备注 |
参数 |
attr |
指定要销毁的参数 |
1.若attr已经不再使用了,则应调用pthread_attr_destroy销毁,此操作对已经创建的线程无影响 2.已经销毁的attr可再次初始化,若后续函数使用已经销毁的attr,则会导致不确定的结果 |
返回值 |
int |
成功返回0,失败返回非0 |
pthread_attr_setstack
1 2
| int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); 功能:设置线程的栈地址和栈大小
|
|
名称 |
说明 |
备注 |
参数 |
attr |
已初始化的attr参数 |
注意:该函数是为了那些需要将栈放在指定位置的线程提供的,默认情况下应避免使用该函数 |
stackaddr |
指向栈空间的最低字节 |
stacksize |
指定了栈空间的大小 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_attr_setstacksize
1 2
| int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 功能:设置线程的栈大小
|
|
名称 |
说明 |
备注 |
参数 |
attr |
已初始化的attr参数 |
无 |
stacksize |
指定了栈空间的大小 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_attr_setdetachstate
1 2
| int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 功能:设置attr参数中的detach属性
|
|
名称 |
说明 |
备注 |
参数 |
attr |
已初始化的attr参数 |
不调用该函数,默认为joinable |
detachstate |
PTHREAD_CREATE_DETACHED:线程属性是detached的 PTHREAD_CREATE_JOINABLE:线程属性是joinable的 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_attr_setinheritsched
1 2
| int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched); 功能:设置attr的继承调度策略
|
|
名称 |
说明 |
备注 |
参数 |
attr |
已初始化的attr参数 |
继承调度策略决定了线程的调度策略是继承线程创建者,还是attr中指定的 |
inheritsched |
PTHREAD_INHERIT_SCHED:继承线程创建者的调度策略,attr参数中的相关属性将被忽略 PTHREAD_EXPLICIT_SCHED:使用attr参数中指定的调度策略 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_attr_setschedparam
1 2
| int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param); 功能:设置attr的调度参数
|
|
名称 |
说明 |
备注 |
参数 |
attr |
已初始化的attr参数 |
该函数设置了attr中,关于线程调度的参数,该参数如下:
struct sched_param {
int sched_priority; /* Scheduling priority */
}; 即调度的优先级,系统支持的最大和最小的优先级值可以用函数: sched_get_priority_max和sched_get_priority_min得到 |
param |
调度参数 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_attr_setschedpolicy
1 2
| int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); 功能:设置attr的调度策略
|
|
名称 |
说明 |
备注 |
参数 |
attr |
已初始化的attr参数 |
该函数设置的调度策略决定了使用attr参数创建的线程的调度策略,如policy所示,前两种均需要设置调度的优先级,数值越大优先级越高,且这两种方式均支持高优先级抢占,而RR不同的是设置了最大运行的时间片。 而SCHED_OTHER的优先级永远是0,它是标准的Linux分时调度程序,适用于不需要特殊实时机制的所有线程。 |
policy |
调度策略: SCHED_FIFO:先入先出 SCHED_RR:轮转法 SCHED_OTHER:其他方法 |
返回值 |
int |
成功返回0,失败返回错误码 |
线程退出
pthread_join
1 2
| int pthread_join(pthread_t thread, void **retval); 功能:等待线程终止
|
|
名称 |
说明 |
备注 |
参数 |
thread |
等待的线程ID |
1.若线程已经终止,则该函数立刻返回 2.若retval不是NULL,则将线程退出状态通过该参数返回,若线程是被cancel的,则返回PTHREAD_CANCELED 注意:这里的retval使用二级指针,是因为pthread_exit返回的终止状态是一个指针,而我们要拿到这个指针就必须传入一个指针的地址。 |
retval |
线程退出状态 |
返回值 |
int |
成功返回0,失败返回错误值 |
线程终止的情况
- 调用pthread_exit,且将线程退出状态通过参数传递给pthread_join
- 从线程函数return,效果同上
- 线程被取消
- 进程中的任意线程调用exit,或者主线程返回,都会导致所有线程终止
pthread_detach
1 2
| int pthread_detach(pthread_t thread); 功能:将线程变为detach状态
|
|
名称 |
说明 |
备注 |
参数 |
thread |
指定线程ID |
线程detach后,则由系统自动回收线程资源,无需主动join |
返回值 |
int |
成功返回0,失败返回错误值 |
joinable和detached状态
- 若是joinable的,则其他线程可调用pthread_join来等待该线程终止并获取退出状态,且必须通过该方式来回收线程资源
- 若是detached的,则无需主动pthread_join,线程退出后资源会被自动回收,且无法获取线程退出状态
- 默认创建的线程是joinable的,除非主动设置attr(pthread_attr_setdetachstate)
pthread_exit
1 2
| void pthread_exit(void *retval); 功能:终止线程并返回终止状态
|
|
名称 |
说明 |
备注 |
参数 |
retval |
函数返回状态 |
1.通过*retval将终止状态返回给pthread_join 2.执行所有注册的线程清理函数 |
返回值 |
void |
无 |
线程取消
pthread_setcancelstate
1 2
| int pthread_setcancelstate(int state, int *oldstate); 功能:设置本线程是否允许被cancel
|
|
名称 |
说明 |
备注 |
参数 |
state |
可被取消属性: PTHREAD_CANCEL_ENABLE:可被取消 PTHREAD_CANCEL_DISABLE:不可被取消 |
默认是可被取消的 |
oldstate |
旧的属性将被从该参数返回 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_setcanceltype
1 2
| int pthread_setcanceltype(int type, int *oldtype); 功能:设置本线程的取消类型
|
|
名称 |
说明 |
备注 |
参数 |
type |
取消类型: PTHREAD_CANCEL_DEFERRED:延迟取消,直到遇到取消点(若取消点在信号处理函数中也可生效,这样效果就和异步取消很相似了)
PTHREAD_CANCEL_ASYNCHRONOUS:异步取消,线程可以随时取消(通常在收到取消命令后立刻取消,但系统不对此保证) |
默认类型是PTHREAD_CANCEL_DEFERRED |
oldtype |
旧的属性将被从该参数返回 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_testcancel
1 2 3
| void pthread_testcancel(void); 功能:设置取消点 说明:在PTHREAD_CANCEL_DEFERRED模式下,当线程执行到该函数时,则可相应取消,若该线程不可取消或者无取消请求,则该函数无作用
|
pthread_cancel
1 2
| int pthread_cancel(pthread_t thread); 功能:取消线程
|
|
名称 |
说明 |
备注 |
参数 |
thread |
取消的线程ID |
1.实测cancel可使正在阻塞的线程强制退出
2.若目标线程是不允许被cancel的,那么该函数发出的cancel请求会被遗留直到目标线程可被cancel再继续响应 |
返回值 |
int |
成功返回0,失败返回错误码 |
pthread_cleanup_push
1 2
| void pthread_cleanup_push(void (*routine)(void *), void *arg); 功能:注册线程清理函数
|
|
名称 |
说明 |
备注 |
参数 |
routine |
线程清理函数 |
注册线程的退出函数,当以下情况时,调用处理函数:
(1)线程被取消
(2)调用pthread_exit
(3)调用pthread_cleanup_pop,且参数不为0,此时只会执行顶层的一个清理函数
注意:从线程中return不用调用处理函数
|
arg |
线程清理函数的参数 |
返回值 |
void |
无 |
pthread_cleanup_pop
1 2
| void pthread_cleanup_pop(int execute); 功能:执行(撤销)线程清理函数
|
|
名称 |
说明 |
备注 |
参数 |
execute |
为0时,撤销顶层线程清理函数 非0时,执行顶层线程清理函数 |
1.实测cancel可使正在阻塞的线程强制退出
2.若目标线程是不允许被cancel的,那么该函数发出的cancel请求会被遗留直到目标线程可被cancel再继续响应 |
返回值 |
void |
无 |
注意,这两个函数的实现是两个宏,pthread_cleanup_push包含了“{”,pthread_cleanup_pop包含了“}”,所以这两个函数必须成对出现