进程创建完线程之后,地址空间没有变化,进程退化成了线程——主线程。
创建出的子线程和主线程共用地址空间,但主线程和子线程有各自独立的pcb,
子线程的pcb是从主线程拷贝来的。
- 在Linux下:
- 内核只看pcb,所以在Linux看起来,线程就是进程,轻量级的进程。
- 多线程和多进程的区别:
- 多进程:
- 始终共享的资源:
- 代码
- 内存映射区
- 文件描述符
- 始终共享的资源:
- 多线程共享资源
- 堆
- 全局变量
- 多进程:
线程更节省资源,内核只认pcb,看到这么多pcb就分配这么多时间片过来,效率不变,但线程资源占用的更少了。
主线程和子线程
- 共享:
- .text
- .bss
- .data
- 堆
- 动态库加载区
- 环境变量
- 命令行参数
- 通信:全局变量,堆
- 不共享:
- 栈区
- 如果有5个线程,栈区被平均分成5分
创建线程
函数原型:
- 12345678//如果成功0,失败返回错误号//不能使用perror()了,因为没有生成errornumberint pthread_create(pyhread_t* thread,//线程ID(无符号长整数),是传出参数const pthread_attr_t *attr,//线程属性,NULLvoid*(*start_routine)(void*),//线程处理函数void *arg //线程处理函数参数)
例
1234567891011121314151617181920void* myfunc(void* arg){// 打印子线程的idprintf("child thread id: %lu\n",pthread_self());return NULL;}int main(int argc,const char* argv[]){//创建一个子线程//线程IDpthread_t pthid;pthread_create(&pthid,NULL,myfunc,NULL);printf("parent thread id:%lu\n",pthread_self());sleep(2);return 0;}
编译时要连接库:-lpthread
线程思维
例如如下代码,运行时不会按照预期:
运行时,线程打印的i-th有重复的,
原因是因为线程抢占cpu时是分片的:
几个线程获得的都是主线程的i的内存地址,而这个i一直都是变化的。
打印返回错误信息
|
|
单个协程退出
函数:void pthread_exit(void *retval);
- retval 指针会带一些信息,必须指向全局或堆的。退出不携带信息则用NULL
阻塞等待线程退出
并获取线程退出状态
函数:int pthread_join(pthread_t thread,void **retval);
- thread:要回收的子线程的线程id
- retval:读取线程退出的时候携带的状态信息
- 传出参数
- void *ptr;
- pthread_join(pthid,&ptr);
- 指向的内存和pthread_exit参数指向同一块内存地址
线程分离
一般线程分离是在线程创建时pthread_create的线程属性设置分离。
也可以使用pthread_detach进行设置线程分离,但不常用。
函数:intpthread_detach(pthread_t thread);
- 调用该函数之后不需要pthread_join
- 子线程会自动回收自己的pcb
使用设置属性设置线程分离
|
|
杀死(取消)线程
函数:pthread_cancel(ptread_t thread);
- 注意事项:
- 在要杀死的子进程对应处理的函数内部,必须做一次系统调用。
- 没有调用系统调用的地方可以使用
pthread_testcancel
设置一个取消点
多线程数据混乱
原因:
- 多线程操作了共享的资源
- 因为cpu调度问题
解决:
- 线程同步
- 什么叫同步
- 协同步调,按照先后顺序执行操作
- 锁
- 本来多线程访问共享资源的时候,可以并行,通过加锁机制,并行——>串行。