进程间通讯(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之后父子各自对锁的操作是不可见的 ④子线程创建的线程中执行了加锁→死锁,锁的状态仍然被子进程继承了。
标签:fork,加锁,互斥,线程,进程,多线程 From: https://www.cnblogs.com/dhwcpp/p/16812147.html