1.
出现上面的问题是基于两个原因:errno是线程之间共享的全局变量;线程之间的相互执行顺序是不确定的。消除第一个原因的办法就是限制全局变量,给每一个线程一个私有的errno,但是这在一定范围内是违背了线程设计的初衷,就是资源的共享,提高资源的利用率。消除第二个原因的办法就是让线程之间的相对执行顺序在需要的时候可以确定。引入线程的一个最具大的问题其实就是多线程的执行结果可能是不确定的,其次是执行效率,为了最大的消除这种多线程执行结果的不确定性,我们引出了线程的同步。
2. 两个或多个线程竞相访问同一段代码或访问同一个资源的现象称为竞争,这个可能造成竞争的共享代码或资源称为临界区。竞争可能有代码的竞争和数据变量的进程。
3. 锁有两个基本操作:闭锁和开锁。
1)闭锁操作有两个步骤,分别如下:等待锁达到打开状态;获得锁并锁上。
2)开锁就一步:打开锁。
注:闭锁的操作应该是原子操作,即不能分开,不然就会留下穿插的空档,从而造成锁的失效。这里又有另一个问题等待会造成资源的浪费,并且可能造成CPU调度的优先级倒挂,优先级倒挂就是高优先级的线程等待低优先级的线程。必须有防止死锁的机制。
4.我们引出又一种机制来解决等待可能产生的问题,就是休眠和叫醒。一个程序进入休眠状态将释放其所占用的资源。
5.为了解决线程的同步,我们发明了锁,但锁的出现带来了循环等待,为了消除循环等待,我们发明了休眠和叫醒,休眠和叫醒又带来了死锁的问题,因此我们再次发明了信号量,那么信号量是不是我们的终极原语呢?信号量又带来了什么问题?使用信号量原语时,信号量操作的顺序至关重要,稍有不慎,就可能死锁。如果一个程序有很多信号量时,程序员将很难搞清楚准确的顺序到底是什么,这是死锁和低效率几乎是肯定的,如是我们又改进引入管程的机制,它监视的就是进程或线程的同步操作。
6.
7.管程的最大问题就是对编译器的依赖,另外管程只能在单台计算机上发挥作用,如果我们想在多计算机环境下进行同步(如网络环境),就又引出了消息传递的机制。消息传递是当前使用非常普遍的线程同步机制。
8.