信号量是什么?
信号量是实现同步的核心工具,核心作用是管控共享资源的访问权限,我们用生活场景来理解:
比如一个有100个车位的停车场,100个车位就是共享资源,当前已停车的数量就是信号量的数值。当停车数没到100时,有空闲车位,车辆可进入;停车数满100后,新车辆必须等待,直到有车驶出(停车数减少,信号量减1),才能进入(停车数增加,信号量加1),这就是典型的计数型信号量,本质是通过计数管控资源的使用量。
和自旋锁相比,信号量的核心优势是能让等待的线程“睡一觉”,不用一直占用CPU死等。就像合租时厕所被占用的场景:B想用厕所,若选择在门口一直等,就是自旋锁的模式,会持续消耗CPU;若选择告诉A“用好喊我”,然后回房间睡觉,就是信号量的模式。信号量让等待线程休眠,能提升CPU利用率,但代价是开销更大——因为休眠会触发线程切换,切换过程会产生额外消耗。
信号量的适用规则很明确:
适合资源占用时间长的场景,等待线程休眠能避免CPU浪费;
绝对不能在中断中使用,因为中断不能休眠,调用信号量会导致系统卡死;
不适合资源占用极短的场景,频繁休眠和线程切换的开销,比自旋锁的高效等待更费资源。
信号量的数值决定了它的类型:初始化时数值大于1,就是计数型信号量,允许多个线程同时访问共享资源;数值固定为1,就是二值信号量,只能一个线程独占资源,实现互斥访问。
信号量怎么用?
Linux内核用专门的结构体表示信号量,使用信号量只需两步:先定义,再初始化,之后按规则申请和释放。
核心操作围绕几个关键函数展开:
定义并初始化信号量:可以直接初始化为1,也可以用函数手动设置初始数值;
申请信号量:分三种情况,一种是申请不到就休眠等待,且等待过程不能被信号打断;另一种是申请不到也休眠,但能被信号唤醒,更灵活;还有一种是不休眠,申请不到直接返回,适合非阻塞场景;
释放信号量:用完后释放,让等待的线程能被唤醒。
信号量的标准使用流程很简单:先定义信号量并初始化,进入临界区前申请信号量,操作完临界区后释放信号量,以此保证共享资源的安全访问。
简言之,信号量是内核中管理共享资源的高效工具,通过计数和休眠等待的机制,既保障了资源访问的秩序,又避免了CPU的无效消耗,尤其适合资源占用时间较长的场景。