3.内核同步之竞争条件和临界区

本文探讨了内核同步的重要性,解释了为什么需要内核同步来保护共享资源,避免并发访问导致的竞争条件。文中还介绍了临界区的概念及信号量的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么需要内核同步?

1)在使用共享内存的应用程序中,程序员必须特别留意保护共享资源,防止共享资源并发访问。

2)Linux作为多任务系统,能够同时运行几个进程。通常各进程必须尽可能保持独立,避免彼此干扰。但有时候应用程序必须彼此通信:

  1. 一个进程生成的数据传输到另一个进程;
  2. 进程必须彼此等待时;
  3. 需要协调资源的使用时。

多个进程对共享资源的并发访问,并发访问会导致竟态。

用户空间应用程序和内核自身都需要保护资源,特别是后者。在SMP系统上,各个CPU可能同时处于核心态,在理论上可以操作所有现有的数据结构。为了防止CPU彼此干扰,需要通过锁保护内核的某些方位。锁可以确保每次只能有一个CPU访问被保护的范围。

2.临界区与竞争条件

临界区就是访问和操作共享数据的代码段。为了避免在临界区中并发访问,编程者必须保证这些代码原子地执行---操作在执行结束前不可能被打断,就如同整个临界区是一个不可分割的指令一样。如果两个执行线程有可能处于同一个临界区中同时执行,那么这就是程序包含的一个bug。如果发生几个进程在访问资源时彼此干扰的情况下我们称它是竞争条件,也就是线程竞争。避免并发和防止竞争条件称为同步。举例:银行存款,统一账户,两个人同时操作,会出现坏账。

这种保证互斥和排他原则,应不依赖所涉及处理器的数目和速度。临界区需要以某种互斥机制加以保护。

3.信号量

针对各种进程间通信提出的一种简单的方法,这里讲述的是应用层使用的是信号量!

原理:

信号量只是受保护的特别变量,能够表示正负整数,其初始值为1;

为了操作信号量,定义了两个标准操作:up和down。这两个代码分别控制关键代码范围的进入和退出,且假定相互竞争的进程访问信号量机会均等。

在一个进程想要进入关键代码时候,调用down函数。这会将信号量的值减1,即将其设置为0,然后执行危险代码段。在执行完操作之后,调用up函数将信号量加1,即重置为初始值。

应用层使用信号量出现的两个特性:

  1. 第二个进程进入危险代码段时候,发现信号量是0,则等待“睡眠”,会一直等待第一个进程退出。从应用程序看该操作是一个原子操作,不能被打断,因此竟态永远不会发生。内核角度看,查询变量的值和修改变量的值是两个不同的操作,但用户将二者视为一个操作。当进程在信号量上睡眠时,内核将其置于阻塞状态,并与其它在该信号量上等待的进程一同放到一个等待列表上。
  2. 进程退出危险代码时,执行up操作。不仅会将信号量的值加1,还会选择一个在该信号量上睡眠的进程。该进程恢复执行时,会进行down操作。

如果没有内核的支持,这个过程是不可能的,因为用户空间库无法保证down操作不被中断。因此应讨论内核对关键代码的保护机制,这是用户程序使用保护的基础。

信号量在用户层可以正常工作,原则上可以用来解决内核内部各种锁的问题。但实际上不是这样:虽然信号量看起来容易实现,但其开销对内核来说过大。这也是内核中提供了许多不同的锁和同步机制的原因。

下一篇我们来看下内核中的锁!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值