POSIX线程库:
与线程有关的函数构成一个完整的系列,大多数函数的名字以“pthread_”开头,而要使用这些函数需要引入头文件<pthread.h>,在编译时需追加-lpthread链接函数库
#线程创建:
//功能:创建一个线程
//函数原型:
int pthread_creat(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void*), void *arg);
thread:返回线程id
attr:设置线程属性,一般置NULL
start_routine:函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0,失败返回错误代码
##线程id:
在Linux中,目前的线程实现是Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)。
struct task_struct{
pid_t pid;
pid_t tgid;
...
struct task_struct *group_leader;
struct list_head thread_group;
};
多线程的进程,又被称为线程组,线程组内的每一个线程在内核之中都存在一个进程描述符(task_struct) 与之对应。进程描述符结构体中的pid,表面上看对应的是进程ID,其实不然,它对应的是线程ID;进程描述符中的tgid,含义是Thread Group ID,该值对应的是用户层面的进程ID.
ps命令中的-L选项,会显示如下信息:
- LWP:线程ID,既gettid()系统调用的返回值
- NLWP:线程组内线程的个数
线程组内的第一个线程,在用户态被称为主线程(main thread),在内核中被称为group leader,内核在创建第一个线程时,会将 线程组的ID的值设置成第一个线程的线程ID,group_leader指针则指向自身,既主线程的进程描述符。所以 线程组内存在一个线程ID等于进程ID,而该线程即为线程组的主线程。
/* 线程组ID等于线程ID,group_leader指向自身 */
p->tgid = p->pid;
p->group_leader = p;
INIT_LIST_HEAD(&p->thread_group);
##线程地址空间
- pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是 一回事。
- 前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要 一个数值来唯一表示该线程。
- pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
- 线程库NPTL提供了pthread_ self函数,可以获得线程自身的ID:
- 对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就 是一个进程地址空间上的一个地址。