pthread_create函数
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg);
pthread_create函数的第一个参数是pthread_t类型的指针,线程
创建成功的话,会将分配的线程ID填入该指针指向的地址。线程的
后续操作将使用该值作为线程的唯一标识。
第二个参数是pthread_attr_t类型,通过该参数可以定制线程的
属性,比如可以指定新建线程栈的大小、调度策略等。如果创建线
程无特殊的要求,该值也可以是NULL,表示采用默认属性。
第三个参数是线程需要执行的函数。创建线程,是为了让线程
执行一定的任务。线程创建成功之后,该线程就会执行start_routine
函数,该函数之于线程,就如同main函数之于主线程。
第四个参数是新建线程执行的start_routine函数的入参。
新建线程如果想要正常工作,则可能需要入参,那么主线程在调用pthread_create的时候,就可以将入参的指针放入第四个参数以传递给新建线程。
如果线程的执行函数start_routine需要很多入参,传递一个指针就能提供足够的信息吗?线程创建者和线程约定一个结构体,创建者便把信息填入该结构体,再讲结构体指针传递给子进程,子进程只要解析就能取出需要的信息。
如果成功,则pthread_create返回0;如果不成功,则pthread_create返回一个非0的错误码。
线程ID及进程地址空间布局
pthread_create函数,会产生一个线程ID,存放在第一个参数指向的地址中。该pthread_t 和 pid 是一回事吗?
不,不是的。
pid属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一标识该线程。
pthread_create函数产生并记录在了第一个参数指向地址的线程ID中,属于线程库的范畴,线程库的后续操作就是根据该线程ID操作线程的。就Linux目前使用的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。
pthread_t到底是个什么样的数据结构呢?因为POSIX标准并没有限制pthread_t的数据类型,所以该类型取决于具体实现。对于Linux目前使用的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。
地址空间布局如图:
主线程的栈大小并不是固定的,要在运行时才能确定大小,因此,在栈中不能存在巨大的局部变量,病外编写递归函数时一定要小心,递归不能太深,否则很可能耗尽栈空间。
由于主线程的栈大小并不是固定的,要在运行时才能确定大小,因此,在栈中不能存在巨大的局部变量,另外编写递归函数时一定要小心,递归不能太深,否则很可能耗尽栈空间。
进程地址空间之中,最大的两块地址空间是内存映射区域和堆。堆的起始地址特别低,向上扩展,mmap区域的起始地址特别高向下扩展。
用户调