线程的操作包括线程的创建,退出和终止,阻碍和分离,取消和清理等。
1. 创建线程
在Linux中,可以调用 pthread_create 函数创建一个新的线程。
#include <pthread.h>
int pthread_create(pthread_t *thread,pthread_attr_t *attr,void*(*start_routine)(void*),void *arg);
如果创建成功则返回0,否则返回错误编号。
- 参数 thread:线程的标识符,这个参数并不是由用户所确定的,用户只需要声明一个 pthread_t 类型的数据变量,并且将值传递给pthread_create函数,函数在创建新的线程时会将新的线程标识符放到这个变量中。
- 参数 attr:指定线程的属性,也可以将其设置为NULL。
- 参数 start_routine:用于指定开始运行的函数,新创建的线程是从这个函数开始运行的,用户需要指定这个函数。
- 参数 arg:这是函数 start_routine 所需要的参数,是一个无类型指针,如果需要传递的参数不止一个,则需要将这些参数都放到一个结构中,然后将这个结构的地址传给 arg。
2. 线程等待
当一个线程执行完成后,可以被其他的线程阻塞挂起,然后等待指定的线程调用 pthread_exit,以便从启动例程中返回或者被取消,Linux 内核可以调用 pthread_join 函数来完成对线程的阻塞。
#include <pthread.h>
int pthread_join(pthread_t thread,void**retval);
对于每一个可连接的线程都必须调用该函数一次。任何线程都不能对相同的线程调用此函数,如果调用成功,则函数返回0,否则返回一个非0值。
- 参数thread:线程标识符,用于指定要等待其终止的线程。
- 参数retval:用于存放其他线程的返回值。
3. 退出线程
线程可以通过三种方式退出,在不终止整个进程的情况下停止线程的控制流。
- 线程只是从启动例程中返回,返回值是线程的退出码。
- 线程可以被同一个进程中的其他线程终止。
- 线程调用 pthread_exit 函数退出。
Linux 内核提供了 pthread_exit 函数用于主动退出线程。
#include <pthread.h>
void pthread_exit(void *retval);
该函数没有返回值,参数 retval 是线程的终止状态,是由用户先指定并且传递给函数的一个参数,在 pthread_exit 函数完成之后可以调用这个参数,以获得进程的退出状态。
4. 取消和清理线程
在 Linux 中,线程可以通过调用 pthread_cancel 函数来请求取消同一进程中的其他线程。
#include <pthread.h>
int pthread_cancel(pthread_t thread);
参数 thread 是需要取消的线程的标识符,函数操作成功时返回0,否则返回对应的错误编号。
在调用 pthread_cancel 函数取消了一个线程之后,需要调用相应的函数对进程退出之后的环境进行清理,这些函数被称为线程清理处理程序,线程可以建立多个清理处理程序。
![](/qrcode.jpg)
#include <pthread.h>
void pthread_cleanup_push(void(*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);
- pthread_cleanup_push 函数将子程序 routine 连同它的参数 arg 一起压入当前线程的 cleanup 处理程序的堆栈;当当前线程调用 pthread_exit 或者是通过 pthread_cancel 终止执行时,堆栈中的处理程序将按照压栈时的相反顺序依次调用。
- pthread_cleanup_pop 函数从线程的 cleanup 处理程序堆栈中弹出最上面的一个处理程序并执行它。
- 两个函数都没有返回值。
真正对线程执行清理工作的是在 pthread_cleanup_push 中作为参数传递进去的 routine 函数,其参数通过 arg 传递进去,在线程执行如下动作的时候被调用:
- 调用 pthread_exit 函数时。
- 响应取消请求时。
- 利用非 execute 参数调用 pthread_cleanup_ pop 时。
如果 execute 参数被置为“0”时,清理函数不会被调用,无论在哪种情况下,pthread_cleanup_pop 都将删除 pthread_cleanup_push 调用建立的清理处理程序。
分离线程
- 在 Linux 中,线程有分离和非分离两种状态。默认情况下是非分离状态,父进程维护子线程的某些信息并等待子线程的结束,在没有显示调用 join 的情形下,子线程结束时, 父线程维护的信息可能没有得到及时释放,如果父线程中大量创建非分离状态的子线程(在 Linux 系统中使用 pthread_create 函数),可能会出现堆栈空间不足的错误,其出错的返回值是12。对于分离线程来说,不会有其他的线程等待它的结束,运行结束后,线程终止,资源及时释放。
- 线程分离就是将线程的 joinable 属性设置为 detach 属性,处于 detach 属性的线程,退出后,将自动回收资源;被分离的线程资源自动被释放,因此不需要等待。
- 分离一个线程的使用场景:用户根本不关心线程的处理结果。
在Linux内核中,可以调用 pthread_detach 函数来进行线程的分离。
#include <pthread.h>
int pthread_detach(pthread_t thread);
参数 thread 是需要分离的线程标识符,函数调用成功则返回0,否则返回错误编号。