第八章、Linux上的多线程编程
1.线程的概念(总述
多线程:一个主线程两个函数线程
Q:进程和线程的区别?
**进程:**在linux系统中,操作系统为每个进程分配4G的虚拟地址内存空间
**线程:**是进程内部的,每个线程都会占用一个栈
类比关系:
2.线程的实现方式
1.用户级线程(从哲学层次看操作系统)
优缺点:
2.内核级线程
优缺点:
3.组合级线程
4.Linux系统上线程的实现方式
其实就是内核级线程
创建线程和创建进程内核调用的方法是一致的,只是传递的参数标记不同。
5.线程和进程的区别
3.Linux上线程的使用
1.线程库中的方法介绍与使用
1.1线程创建
线程方法的实现实是在专有的线程库中
问题:undefined,因为头文件里是声明
加一个动态库的方法
ldd查看一下
结果
结论:
1.2线程函数的传参
1.2.1值传递实例
1.2.2地址传递
2.线程并发
结果:
原因:
线程是并发执行的,有可能两个线程是同时执行的,比如g本来是1,两个线程同时执行,在内存中取值1,然后都对1加了一次,都变成了2,又写入内存。效果就是只加了一次
5.Q:让主线程比线程函数的执行时间短
重点:结束线程的方法十分重要
原因
结束线程方法的使用:
等待线程结束方法的使用:会变成串行执行了,所以一般不常使用
3.验证线程之间的数据共享
.data .bss数据段 和 .heap堆区
结果
内核:文件描述符
结论:任何一个线程打开的文件在其他线程中可以访问,即共享文件描述符
4.线程同步
与进程同步的目的相同
1.在访问临界资源时需要同步(间接制约关系
2.要相互配合着执行(直接制约
1.互斥锁(互斥量)
1.1例1:aaaaabbbb
结果
2.信号量(线程级的信号量)
进程是由操作系统控制的,所以使用的方法我们需要自己封装。
而线程这边的方法是由线程库提供的,库里已经给我们封装好了方法,不需要我们自己动手了。
2.1例1:主进程获取用户数据输入,函数线程将用户输入的数据存储到a.txt中
结果:
3.条件变量:为多个线程提供了一个汇合场所
条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程。
4.读写锁
5.线程安全
一个好博文
线程安全的解决方式:
1.使用线程同步(eg.在函数线程 开始和结束前,加互斥锁)
2.不使用共享的数据
函数线程的栈区
== buff在主线程的栈区==
结果:
Q:为什么主线程能看见函数线程的buff?
stork方法要记录数据,下次切割还能记得,所以数据的存储位置必定不能在该函数的栈区,不然调用完就销毁了,所以数据应该保留在.data或者.bss数据区,所以线程又不安全了
用stork_r方法可以解决安全问题
结果:
5.1线程安全问题举例
结果不确定:
**原因:**执行++如果是串行执行肯定是10000,由于是并行运行了,所以出现值不确定的问题,因此要考虑线程安全
6.线程与fork
atfork注册这三个方法,以及其调用时机,都是为了保证在fork执行过程中,所有的锁都是加锁状态的。没有其他线程会加锁成功。fork完成之后, 再主动对所有的锁,分别在父进程空间和子进程空间解锁。fork之后, 父好进程的使用的锁都是解锁状态的。