1.和并发相关的一些关键术语
原子操作:一个或多个指令的序列,对外是不可分的;即没有其他进程(线程)可以看到其中间状态或中断此操作。
临界区:是一段代码,在这段代码中进程将访问共享资源,当一个进程已经在这段代码中运行时,其他进程就不能在这段代码中执行。
死锁:两个或多个进程因其中每个进程都在等待其他进程做完某些事情而不能继续执行。通俗地讲就是分割整体资源,各占有部分。
活锁:两个或多个进程为了响应其他进程中的变化而持续改变自己的状态但不做有用的工作。
互斥:当一个进程在临界区访问共享资源时,其他进程不能进入该临界区访问任何共享资源。
竞争条件:多个进(线)程读写共享区数据时,结果依赖于它们执行的相对时间(顺序)。
饥饿:指一个可运行的进程尽管能继续执行,但被调度器无限期地忽略,而不能被调度执行。
2.互斥的硬件支持
由于并发性,所以要实现互斥。
2.1中断禁用
在单处理器机器中,进程交替执行。因此为保证互斥只要在进程执行的过程中禁用中断就可以了,这可以通过系统内核为启动禁用中断定义的原语来提供。这种过程如下:
while(true)
{
/*禁用中断*/
/*临界区*/
/*启动中断*/
/*其余部分*/
}
缺点:代价太高,第一这样处理器只能交替执行程序,因此效率将会有明显的降低。第二不适用于多处理器机构,因为可能有一个以上的进程同时执行。
2.2专用机器指令
比较和交换指令——该令是用一个测试值(testval)检查一个内存单元(*word)。
int compare_and_swap(int *word, int testval, int newval)
{
int oldval;
oldval = *word;
if(oldval == testval) *word = newval; //相等所以内存没有改变,内存改为新值
return oldval; //返回旧内存值
}
所以如果返回的内存值与测试值相同,那么内存被更新了。如此多个进程就可以一直检测某内存(假设0允许进入1不允许进入),这样首先发现该内存值为0的进程就可以进入临界区,并将该内存值置为1,阻止其他进程进入。
机器指令的方法特点:
优点:1、适用于在单处理器或共享内存的多处理器上的任何数目的进程。
2、非常简单易于证明(基本没用)。
3、可支持多个临界区,每个临界区使用它自己的变量定义。
缺点:
1、 使用了忙等待。等待进入临界区的进程会继续消耗处理器时间。
2、 可能饥饿。选择哪一个等待进程是任意的,某些进程可能无限期地拒绝进入(可能性应该很小)。
3、 可能死锁。进程1进入临界区后改变值,之后在进程1执行的过程中进程1被进程2抢占。如果进程2试图使用同一资源,由于进程1控制着该资源,进程2无法访问。所以进程2进入忙等待,但是进程1优先级低于进程2,它将永远不会被调度执行。