0%

进程同步和线程同步

进程同步

  1. 管道

    管道分为命名管道和匿名管道,命名管道可以用于两个或任意多个进程间通信,匿名管道则只能用于有血缘关系(父子进程、兄弟进程、爷孙进程等)的进程间通信。Linux中的“|”命令就是匿名管道,表示把一个进程的输出作为另一个进程的输入。管道就是内核里的一段缓存,从管道一端写入的数据实际上是缓存在内核中,从另一端读取也就是从内核中读取这段数据。管道是半双工的,数据只能向一个方向流动,双方需要互相通信时,需要建立起两个管道。

  2. 消息队列

    多个不相干的进程可以通过一个消息队列来传递数据,且传递的是一个有意义的数据结构,而管道只能传递没有意义的字节流,还需要在接收端做解析。

  3. 共享内存

    共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的一种IPC方式,因为没有内存拷贝的操作,但需要依靠互斥锁或信号量来实现同步。

  4. socket

    可用于不同主机之间的进程间通信。

  5. 信号

    信号是Linux系统中的进程间通信方式,信号可以在任何时候发给某一进程,用于通知该进程某个事件已经发生。比如kill -9命令就可以向指定的进程发送一个终止信号从而杀死进程。

  6. 信号量

    信号量本质就是一个计数器,记录资源能被多少个进程同时访问,用来实现进程之间的互斥与同步,信号量的引入的是为了解决共享内存通信方式造成的进场安全问题。

进程同步和进程通信

  • 进程同步是进程之间按照一定顺序执行,进程通信是进程之间传输信息。

  • 进程通信是一种手段,而进程同步是目的。即为了达到进程同步的目的,需要让进程进行通信,传输一些同步所需要的信息。

线程同步

  1. 互斥锁

    互斥锁是线程同步最常用的一种方式,通过互斥锁可以锁定一个代码块,对于被锁定的这个代码块,所有的线程只能串行处理,不能并行处理。

  2. 读写锁

    读写锁是互斥锁的升级版,所有线程的读操作都是并行的,只有写操作是串行的。程序中的读操作越多,读写锁性能就越高,相反,若程序中全是写操作,那么读写锁会退化成互斥锁。

  3. 条件变量

    条件变量的主要作用不是处理线程同步,而是进行线程的阻塞。常常和互斥锁一起用在生产者和消费者模型中。举个例子:当任务队列为空时,消费者无法消费,使用条件变量把消费者线程阻塞住,等待生产者生产出任务后,再唤醒一个或多个被条件变量阻塞的消费者线程;反过来也可以控制生产者生产的上限,当任务队列达到一个上限值时用条件变量阻塞住生产者线程,直到消费者把任务消费后再唤醒被条件变量阻塞的生产者线程。

  4. 信号量

    信号量可以实现线程同步也可以实现进程同步,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。信号量主要阻塞线程,不能完全保证线程安全,如果要保证线程安全,需要和互斥锁一起使用。信号量也可以用来实现生产者消费者模型,在用条件变量实现生产者消费者模型时需要自己做条件判断,而使用信号量就不需要。举个例子:初始化生产者的信号量为5,消费者的信号量为0,因为消费者信号量为0所以会被阻塞,生产者进行一次生产后会将自己的信号量减1,将消费者信号量加1,这时消费者解除阻塞,进行消费后再将自己的信号量减1生产者信号量加1。

  5. 自旋锁

    自旋锁与互斥锁类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。自旋锁可用于一下情况:锁被持有的时间短,而且线程并不希望在重新调度上花费太多成本。

  6. 屏障

    屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后从该点继续执行。pthread_join函数就是一种屏障,允许一个线程等待,直到另一个线程退出,但屏障允许任意数量的线程等待,直到所有的线程完成处理工作,而线程不需要退出,所有线程达到屏障后可以接着工作。

信号量和互斥锁

  • 互斥锁是由一个线程持有的,加锁和解锁操作在一个线程中执行。而信号量可以由不同线程进行PV操作。
  • 互斥锁用于控制多个线程对于一个共享资源的互斥访问,而信号量用于协调多个线程对于一系列资源的访问。
  • 信号量本质上是一个计数器,其正值代表资源的可用数量,负值代表还有多少个线程在等待资源。

条件变量和信号量

  • 信号量利用条件变量、互斥锁、计数器实现,计数器就是信号量的核心,信号量是条件变量的高级抽象。
  • 使用条件变量可以一次唤醒所有等待者,而这个信号量没有的功能,感觉是最大区别。
  • 信号量是有一个值(状态的),而条件变量是没有的,没有地方记录唤醒(发送信号)过多少次,也没有地方记录唤醒线程(wait返回)过多少次。从实现上来说一个信号量可以是用mutex + counter + condition variable实现的。因为信号量有一个状态,如果想精准的同步,那么信号量可能会有特殊的地方。信号量可以解决条件变量中存在的唤醒丢失问题。

Welcome to my other publishing channels