1 线程常见函数
1.1 线程创建于回收
(1)pthread_create 主线程用来创造子线程
(2)pthread_join 主线程用来等待(阻塞)回收子线程
(3)pthread_detach 主线程用来分离子线程,分离后主线程不必再去回收子线程
小结:线程函数创建的线程,就是里面函数指针指向的函数体,整个函数是一个线程,里面定义,申请的内存资源,当这个线程执行完,可以在主线程main中使用pthread_join回收内存资源,或者用pthread_detach分离出去。
1.2 线程终止
(1) pthread_cancel 一般都是主线程调用该函数去取消(让它赶紧死)子线程
(2)pthread_setcancelstate 子线程设置自己是否允许被取消
(3)pthread_setcanceltype 子线程允许被取消这个后这个函数才有用,他是被取消的方式,什么情况才死
1.3 线程函数退出相关
(1)pthread_exit与return退出 pthread_exit的返回值最后给pthread_join,就是它返回的
(2)pthread_cleanup_push 线程清理压栈相关
(3)pthread_cleanup_pop 清理弹栈相关
小结:(1)不能用exit(0)退出一个线程,他是整个进程的推出函数,pthread_exit的返回的是一个一重指针,所以pthread_join要用一个二重指针来接收它,才能在pthread_join函数体里面对这个一重指针本身进行操作,而不是对一重指针指向的变量操作,pthread_join要操作的是,这个一重指针。操作变量,我们用一重指针接收,操作指针我们用二重指针接收
(2)pthread_cleanup_push,防止线程上锁之后,正常线程处理完后,会被释放锁,但是上锁后,被主线程pthread_cancel取消了,而锁还没有释放,这时用pthread_cleanup_push解开锁(里面绑定了一个开锁函数),放在上锁函数后面,pthread_cleanup_pop用来接应push,详细见视频位置
1.4 获取线程id
(1)pthread_self 获取线程ID,没有进程id重要。
2 线程创建过程
--在进程中只有一个控制线程时
--程序开始运行的时候每个进程只有一个线程,它是以单线程方式启动的,在创建多个线程以前,进程的行为与传统的进程没有区别
--gcc在链接的时候需要增加-lpthread选项(pthread是共享库文件)。
--创建一个线程调用pthread_create函数。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
如果pthread_create成功返回,有thread指向的内存单元被设置为新创建线程的线程ID。
attr参数用于定制各种不同的线程属性。
新创建的线程从start_routine函数地址开始执行,该函数只有一个void *参数,
如果需要向start_routine函数传递多个参数,就需要把这些参数放到一个结构中,然后把这个结构的地址作为void *传入。
线程创建的时候不能保证哪个先运行。
pthread_create函数成功返回0,失败返回非0,并且更新errno。
--注意:每个线程都拥有一份errno副本,不同的线程拥有不同的errno
3 线程终止
--任一线程调用了exit函数,整个进程就会终止。
--如果信号默认动作是终止进程,那么信号发送到该进程,整个进程也会被终止。单个线程通过以下三种方式退出
--线程只是从启动函数中返回,返回值是线程的退出码
--线程可以被同一进程中的其他线程取消。
--线程调用pthread_exit。
void pthread_exit(void * arg);
arg是个无类型指针,该指针会被其他线程调用pthread_join捕捉。
在线程的子函数中调用pthread_exit()函数,线程也会退出,这点跟exit()函数相同。
线程之间是异步的,无法确定哪个线程先执行。
进程内的信号捕捉一般在控制线程内进行
pthread_create()函数的第四个参数对应回调函数的参数