线程控制
POSIX线程库
- 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
- 要使用这些库函数,要引入头文件 pthread.h
- 链接这些线程函数库时要使用编译器命令“-lpthread” 选项
创建线程:
int pthread_create(pthread_t* thread, const pthread_attr_t*
attr, void* (*start_routine)(void*), void* arg)
参数:
thread:返回线程ID
attr:设置线程属性,attr = NULL,表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
举个例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *rout(void *arg){
(void)arg;
while(1){
printf("I am thread 1\n");
sleep(1);
}
}
int main(void){
pthread_t tid;
int ret;
if((ret = pthread_create(&tid, NULL, rout, NULL)) != 0){
fprintf(stderr, "pthread_create:%s\n", strerror(ret));
exit(EXIT_FAILURE);
}
while(1){
printf("I am main thread\n");
sleep(1);
}
}
进程ID和线程ID
- 在Linux中,目前线程实现是Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程又被称为轻量级进程,每一个用户态的线程,在内核中对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)。
- 没有线程之前,一个进程对应内核里一个进程描述符,对应一个进程ID。但是引入线程概念之后,一个用户进程下管辖N个用户态线程,每个线程作为一个独立的调度实体在内核态都有自己的进程描述符,进程和内核的描述符一下变成1 : N的关系,POSIX标准又要求进程内所有线程调用getpid函数时返回相同的进程ID,如何解决上述问题呢?
- Linux引入了线程组的概念。
struct task_struct {
...
pid_t pid;
pid_t tgid;
...
struct task_struct* group_leader;
...
struct list_head thread_group;
...
- 多线程的进程,又被称为线程组,线程组内的的每一个线程在内核中都有一个进程描述符与之对应。进程描述符中的pid对应线程id;进程描述符中的tgid,含义是Thread Group ID,该值对应的是用户层面的进程ID。
线程ID及进程地址空间布局
- pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面所说的线程ID不一样。
- 前面的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一标识一个线程。
- pthread_create函数产生并标记在第一个参数指向的地址中的线程ID中,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
- NPTL提供了pthread_self函数获得自身ID。
pthread_t pthread_self(void)
线程终止
如果要终止某一个进程而不终止整个进程,可以有三种方法:
- 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit.
- 线程可以调用pthread_exit终止自己
- 一个线程可以调用pthread_cancle终止同一个进程中的另外一个线程。
Pthread_exit函数
功能:线程终止
原型: void pthread_exit(void* value_ptr)
参数: value_ptr:value_ptr不要指向一个局部变量
返回值: 无返回值
pthread_cancel函数
功能:取消一个执行中的线程
原型: int pthread_cancle(pthread_t thread);
参数:thread:线程ID
返回值:成功返回0;失败返回错误码
线程等待与分离
线程等待
为什么线程需要等待?
- 已经退出的线程,其空间没有被释放,仍然在进程地址空间内。
- 创建新的线程不会复用刚才退出线程的地址空间。
功能:等待线程结束
原型:
int pthread_join(pthread_t thread, void **value_ptr)
参数:
thread:线程ID
value_ptr:它指向一个指针,该指针指向线程的返回值。
返回值:成功返回0;失败返回错误码。
调用该函数的线程将挂起等待,直到id为thread的线程终止。thread通过不同方法终止,通过phread_join得到的终止码是不同的。
1.如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
2.如果thread线程被别的函数调用phread_cancle异常终止掉,value_ptr所指向的单元里存放的是常数PThREAD_CANCLEED
3.如果thread线程是自己调用pthread_exit ()终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
4.如果对thread线程的终止状态不感兴趣可以穿参数NULL