当操作系统进入多道批处理系统时代以后,一个系统中就存在多个任务,每个任务都按照一定的算法进行调度来使用内存、cpu等共享资源。当其中一个任务等待其他资源时,该任务可以暂时睡眠,操作系统调度另外任务继续执行额,这样可以使系统资源得到最大化利用,而无需像以前单道批处理系统那样只有当一个任务完成之后才执行下一个任务。但是由此也引入了多任务并发的问题。
并发就是多个任务同时执行,在现在的一般大型应用系统中,一个功能基本有多个任务共同完成,每个任务相互协调,互相配合以及交换信息,如此一来,我们需要考虑并发任务的同步与互斥了。
所谓同步,就是一件事情需要按照先后顺序去完成,当一个任务和另一个任务通信时,任务A获取另一个任务B的信息,当任务B未返回信息时,任务A持续等待,直到B返回信息回来,A再继续执行。异步是和同步相对的一个概念,就是任务A向B请求信息时,不必等待B信息的返回,A请求完成之后直接做下一件事情。
所谓互斥就是某些资源在某一时刻只能由一个任务占有,在某资源被任务A占有的情况下,其他需要占有该资源的任务B必须等待,任务A使用完该资源后释放后任务B才能使用该资源。一般这样的资源被称作临界资源,有的时候一段程序不允许并发执行,这段程序被称作临界区。
要解决同步互斥问题, 最主要的是理清楚活动者之间的同步关系, 还有某些问题中变量的互斥问题。我们来看看生产者消费者问题,生产者消费者问题是一个经典的进程同步问题。它描述的是:
有一群生产者进程在生产产品, 并将此产品提供给消费者进程去消费。为使生产者进程和消费者进程能并发执行, 在它们之间设置有个缓冲区的缓冲池, 生产者进程可将它所生产的产品放入一个缓冲区中,消费者进程可从一个缓冲区取得一个产品消费。尽管所有的生产者进程和消费者进程都是以异步的方式运行的,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品, 也不允许生产者进程向一个已装满产品的缓冲区投放产品。
我们这样来描述这个问题, 假如缓冲池中有n个缓冲区,每个缓冲区存放一个消息,生产者和消费者进程(或线程)对缓冲区互斥的访问。只要缓冲池未满,生产者可将消息送入缓冲池;只要缓冲池未空,消费者可从缓冲池取走一个消息。 此时生产者和消费者需要保持同步,当缓冲池为空时,生产者通知消费者不要再来取数据,当不为空时,通知消费者可以来取数据。
在linux中,实现同步与互斥的方法有很多,比如信号量等,线程还有专用的线程互斥锁以及条件变量。本系列文章将对各种实现同步互斥的方法进行分析以及给出示例,并且大多示例都基于生产者消费者模型来阐述。