3、并非只有主线程才能调用pthread_join连接其他线程, 同一线程组内的任意线程都可以对某线程执行pthread_join函数。
4、并非只有主线程才能调用pthread_detach函数, 其实任意线程都可以对同一线程组内的线程执行分离操作。
线程的对等关系:

2.线程创建
接口:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数解释
1、thread:线程标识符,是一个出参
2、attr:线程属性
3、star_routine:函数指针,保存线程入口函数的地址
4、arg:给线程入口函数传参
返回值:成功返回0,失败返回error number
详解:
第一个参数是pthread_t类型的指针, 线程创建成功的话,会将分配的线程ID填入该指针指向的地址。 线程的后续操作将使用该值作为线程的唯一标识。
第二个参数是pthread_attr_t类型, 通过该参数可以定制线程的属性, 比如可以指定新建线程栈的大小、 调度策略等。 如果创建线程无特殊的要求, 该值也可以是NULL, 表示采用默认属性。
第三个参数是线程需要执行的函数。 创建线程, 是为了让线程执行一定的任务。 线程创建成功之后, 该线程就会执行start_routine函数, 该函数之于线程, 就如同main函数之于主线程。
第四个参数是新建线程执行的start_routine函数的入参。
pthread_create错误码及描述:

2.1传入参数arg的选择

不要使用临时变量传参,使用堆上开辟的变量可以。
例:
#include #include #include #include void *ThreadWork(void *arg){ int *p = (int*)arg; printf("i am work thread:%p, data:%dn",pthread_self(),*p); pthread_exit(NULL);}int main(){ int i = 1; pthread_t tid; int ret = pthread_create(&tid,NULL,ThreadWork,(void*)&i);//不要传临时变量,这里是示范 if(ret != 0) { perror("pthread_create"); return -1; } while(1) { printf("i am main work threadn"); sleep(1); } return 0;}
2.2线程ID以及进程地址空间
线程获取自身的ID:
#include pthread_t pthread_self(void);
判断两个线程ID是否对应着同一个线程:
#include int pthread_equal(pthread_t t1, pthread_t t2);
返回为0时,则表示两个线程为同一个线程,非0时,表示不是同一个线程。
用户调用pthread_create函数时, 首先要为线程分配线程栈, 而线程栈的位置就落在共享区。 调用mmap函数为线程分配栈空间。 pthread_create函数分配的pthread_t类型的线程ID, 不过是分配出来的空间里的一个地址, 更确切地说是一个结构体的指针。

即:

2.3线程注意点
1、线程ID是进程地址空间内的一个地址, 要在同一个线程组内进行线程之间的比较才有意义。 不同线程组内的两个线程, 哪怕两者的pthread_t值是一样的, 也不是同一个线程。
2、线程ID就有可能会被复用:
1、线程退出。
2、线程组的其他线程对该线程执行了pthread_join, 或者线程退出前将分离状态设置为已分离。
3、再次调用pthread_create创建线程。
2.4线程创建出来的默认值
线程创建的第二个参数是pthread_attr_t类型的指针, pthread_attr_init函数会将线程的属性重置成默认值。
线程属性及默认值:

如果确实需要很多的线程, 可以调用接口来调整线程栈的大小:
#include int pthread_attr_setstacksize(pthread_attr_t *attr,size_t stacksize);int pthread_attr_getstacksize(pthread_attr_t *attr,size_t *stacksize);
3.线程终止
线程终止,但进程不会终止的方法: