创建线程以后,地址空间没有变化,进程退化成线程. 创建的子线程和主线程公用一份地址空间.
在linux 下 线程就是轻量级进程. 对于linux内核不区分线程和进程
主线程和子线程
共享的部分
- .text
- .bass
- .data
- 堆 动态库加载区 环境变量 命令行参数
- 可以通过 全局变量 或 堆进行通信
不共享的部分
- 栈
观察指定线程的LWP号
线程号和线程id的区别
- 线程号LWP是给内核看的.
- 线程id是给程序员看的
查看方式 - 找到程序的进程id
- ps -Lf pid
多进程和多线程的区别
多进程共享的资源
- 代码
- 文件描述符
- 内存映射区 mmap
进程和线程共享的资源
- 堆
- 全局变量
- 线程节省资源
DEMO
gcc d.c -lpthread
pthread_join 和 pthread_exit 参数接受一个指针, 是一个传出参数.可得到退出状态
int pthread_create(pthread_t *thread, //线程ID 无符号长整形
const pthread_attr_t *attr, //线程属性 .NULL,可以设置线程分离
void *(*start_routine) (void *), //线程处理函数
void *arg) //线程处理函数参数
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
void* myfunc(void* arg){
//打印子线程id
printf("child thread id %d\n", pthread_self());
for(int i=0; i<5;i++){
printf("child i=%lu\n", i);
sleep(1);
}
return NULL;
}
int main(){
pthread_t ptid;
int ret = pthread_create(&ptid, NULL, myfunc, NULL);
if (ret != 0){
printf("pthread err %d\n", ret);
}
printf("parent thread id %lu\n", pthread_self());
for (int i = 0; i < 10; i++)
{
printf("father i=%d\n", i);
}
//如果不加下面这句话. 主线程直接退出,子线程也会退出.
pthread_exit(NULL); //加上这句话, 主线程退出,子线程继续执行.
return 0;
}
线程分离
- int pthread_detach(pthread_t thread); 或者创建线程的时候 设置线程属性
- 调用该函数后,不再需要pthread_join
- 线程会自己回收自己的tcb
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *thrd_func(void *arg)
{
sleep(1);//防止分离的线程在pthread_create返回tid之前结束,导致tid为失败值而认为创建线程失败
pthread_exit((void *)77);
}
int main(void)
{
pthread_t tid;
int ret;
pthread_attr_t attr;
//1
ret = pthread_attr_init(&attr);
if (ret != 0) {
fprintf(stderr, "pthread_init error:%s\n", strerror(ret));
exit(1);
}
//2 设置线程分离
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//3 这一步注意:若pthread_create创建分离的线程后,并且在返回tid之前结束,tid可能是一个失败值。所以可以使分离的线程睡眠一下。
ret = pthread_create(&tid, &attr, thrd_func, NULL);
if (ret != 0) {
fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
exit(1);
}
/*
//这一步只是验证是否成功属性分离,若成功则回收失败
ret = pthread_join(tid, NULL);
if (ret != 0) {
fprintf(stderr, "pthread_join error:%s\n", strerror(ret));
exit(1);
}
*/
//释放资源
pthread_attr_destroy(&attr);
pthread_exit((void *)1);
}
杀死子线程
- pthread_cancel
- 使用注意事项
- 在杀死的子线程对应的处理函数的内部,必须做过一次系统调用.