线程控制
线程控制
简介
我们可以将线程看作为一个依托于进程存在的独立逻辑流,它拥有着独立的线程ID,一组寄存器,栈,调度优先级和策略,信号屏蔽字,errno变量以及线程私有数据.
同时,进程的所有信息对所有线程共享,包括可执行程序的代码,程序的全局内存和堆内存以及文件描述符.
关于所有线程共享进程堆内存的问题我查阅了一些资料.某些blog上说线程在共享堆内存的时候内核是对内存做了同步处理以及读写保护,所以所有的线程共享一个堆也是安全的.
这个问题暂时写在前面,等我翻阅一些资料之后再尝试着解释线程共享堆的机制.
创建线程
-
线程标识:就像每个进程都有一个进程ID一样,每个线程都有一个线程ID,线程ID只有在所属进程的上下文中才有意义.
线程ID是用pthread_t数据类型来表示的,考虑到可移植性问题,我们使用一个函数对两个线程ID进行比较:#include<pthread.h> int pthread_equal(pthread_t tid1, pthread_t tid2) //返回值:若相等则返回非0,否则返回0. pthread_t pthread_self(void) //返回值:调用线程的线程ID
-
函数原型:
#include<pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t * restrict attr, void *(*start_rtn) (void *) void *restrict arg); //成功则返回0,否则返回错误编号.
-
参数tidp:当pthread_create成功返回时新创建的线程ID会被放入tidp指向的内存单元.
-
参数attr:设置不同的线程属性,如果是NULL则为默认属性,后面我们会介绍到.
-
参数start_rtn:新创建的线程从start_rtn函数地址开始运行,如果需要向函数传递参数,那么需要把这些参数放入一个结构中,然后把结构的地址作为arg参数传入.
终止线程
-
进程中可以通过exit退出整个进程,但是如果我们在线程中调用exit则会退出整个进程.下面介绍三种退出线程的方式
- 线程执行完毕从启动例程返回,返回值是线程退出码.
- 线程可以被同一进程中的其他线程取消.
- 线程调用pthread_exit退出.
-
函数原型:
#include<pthread.h> void pthread_exit(void *rval_ptr)
-
rval_ptr参数:无类型指针,作为线程结束的返回值.
获取线程返回值
-
当我们希望阻塞住并等待某个线程终止的时候可以用pthread_join
#include<pthread.h> int pthread_join(pthread_t thread, void **rval_ptr) //成功则返回0,否则返回错误编号.
-
thread参数:指定等待的线程ID
-
rval_ptr参数:获得指定线程调用exit的参数rval_ptr
-
如果线程被取消,则rval_ptr参数则为PTHREAD_CANCELED
-
需要注意的是,当调用exit的时候,我们传入的参数可以是一个复杂结构的指针.同时,这个结构所使用的内存最好在分配在堆上,因为当线程结束时该结构可能已经被释放.
分离线程
-
上文提到,如我们需要通过调用pthread_join来回收一个结束进程的终止状态.如果我们并不关心这种状态也不想造成内存泄露的话要怎么做呢
我们可以函数来对线程进行分离 -
函数原型:
#include<pthread.h> int pthread_detach(pthread_t thread) //成功则返回0,否则返回错误编号.
-
调用了pthread_detach函数的线程在终止后存储器资源会被立即收回
取消同一进程的其他线程
-
函数原型:
#include<pthread.h> int pthread_cancel(pthread_t tid); //成功返回0,失败则返回错误码
-
函数可以令目标线程的行为表现如同执行了pthread_exit(PTHREAD_CANCELED)一样.
-
目标线程可以选择忽略取消或者控制如何被取消,cancel函数并不等待线程终止,而是仅仅提出请求.
线程清理处理程序
-
线程可以安排它退出时需要调用的函数,其作用和atexit函数类似.
-
函数原型:
#include<pthread.h> void pthread_cleanup_push(void (*rtn) (void *), void *arg) void pthread_cleanup_pop(int execute)
-
触发条件:
- 调用pthread_exit时.
- 响应取消请求时.
- 用非0 execute 参数调用pthread_cleanup_pop