• 欢迎光临~

进程、线程和多线程

开发技术 开发技术 2022-10-20 次浏览
进程间通讯(IPC):管道、信号量、共享内存、消息队列、套接字
管道:有名 无名(有名无名的区别),在内存中写入,通讯方式:半双工
信号量:特殊变量(一般取值大于等于0)例如0、1 代表资源状态 例如3:代表可访问资源个数
可以对其值进行改变 减一:代表获取资源,一般称为p操作,有可能会发生阻塞,等于0时
加一:释放资源,一般称为v操作
临界资源:同一时刻只允许一个程序访问的资源
临界区:访问临界资源的代码段
 
多线程
进程:一个正在运行的程序,是系统进行资源分配的一个基本单位
线程:系统内的一条执行路径,是进行调度的一个基本单位
线程的实现:用户级、内核级、组合
Linux:内核级
pthread.h pthread_create()创建线程
pthread_exit()退出当前线程
pthread_join()等待线程结束/合并线程
线程的并发运行、线程同步、线程安全
并发运行:同一时刻仅有一个线程运行
并行:多处理器,同一时刻至少有两个线程
 5个线程创建,不一定按顺序,随机,调度,结果是乱的,无法推测,深刻理解并发运行
 
线程同步(线程间通信)
四种方法:互斥锁、信号量、条件变量、读写锁
 
信号量
互斥锁:lock(加锁可能会阻塞),unlock(解锁不会阻塞)
读写锁:可以允许两个线程同时读,读不互斥,但是写会互斥
条件变量:提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程
 
线程安全
在多线程运行的时候,不论线程的调度顺序怎么样,最终的结果都是一样的、正确的
如何保证线程安全:
(1)线程同步,保证同一时刻只有一个线程访问临界资源
(2)使用线程安全的函数(可重入函数),所谓线程安全的函数指的是:如果一个函数能被多个线程同时调用且不发生静态条件,则线程是安全的
s t r t o k()不能在多线程中使用,凡是函数内部使用了静态变量或者全局变量,那么就无法在多线程中使用
s t r t o k( )_r,可以在多线程中使用
 
线程与fork
多线程程序fork后,子进程只有一条执行路径,就是fork所在的执行路径,子进程是不会创建和父进程相同数量的线程的,整个进程的资源是被复制的
 
关于fork()与互斥锁:某个线程调用fork()函数后,子进程会自动集成父进程中(包括父进程在调用fork()之前创建的线程)互斥锁的状态,也就是说,父进程中已经被加锁的互斥锁在子进程中也是被锁住的。即子进程可能不清楚从父进程继承过来的互斥锁的具体状态。这个互斥锁可能被加锁了,但并不是由调用fork函数的那个线程锁住的,而是由其他线程锁住的,如果是这种情况,则子进程再次对该互斥锁执行加锁操作就会导致死锁。
①继承父进程创建的锁→死锁,父进程之前加了锁,子进程继承了之后,尝试加锁会被阻塞,即便父进程解了锁,子进程还是不能加锁,因为fork之后子进程对父进程的动作是不可见的,因此子进程陷入了永远的阻塞
②父进程的子线程在fork之前加了锁→死锁,子线程加锁后,子进程继承了互斥锁的状态,无法执行加锁操作,被阻塞。即便后来子线程解了锁,子进程还是继续阻塞。说明子进程只是继承了锁的状态,对后来的解锁动作并不可见
③子线程在fork之后加锁→正常,在fork之前子线程还没有加锁,子进程成功加锁,再解锁前,子线程也执行了加锁操作,之后两者都顺利解了锁。说明子进程继承的只是fork之前父进程(包括其子线程)已执行过的锁操作状态,fork之后父子各自对锁的操作是不可见的
④子线程创建的线程中执行了加锁→死锁,锁的状态仍然被子进程继承了。
 
程序员灯塔
转载请注明原文链接:进程、线程和多线程
喜欢 (0)