当前位置: 首页 > 图文教程 > 操作系统 > Unix/Linux > 详谈Linux 2_4_x内核信号量机制

Unix/Linux
linux查看内存的大小
在linux下写的代码,用的是utf-8,结果拿到XP下运行的时候,所有的中文都成乱码
linux su和sudo命令的区别
linux cron 下的定时执行工具使用技巧
linux 查找进程及终止进程操作的相关命令
redhat linux 安装 gcc编译器
Linux Mplayer播放各种格式的电影
一起回顾一下linux常用命令
Linux 网站项目发布要做哪些配置
linux SSH配合SecureCRT的密匙完美使用方法
GD 编译出错解决方法
Facebook Open Platform编译FAQ
Linux 系统硬盘 优化
linux 挂载详解
linux crontab定时命令
Linux 系统中确保访问三级域名畅通的方法
Linux 特权帐号VS普通帐号
确保Linux系统安全的前提条件 漏洞防护
Linux 监视系统资源使用率
Red Hat Linux上使用BIND建立DNS服务器

Unix/Linux 中的 详谈Linux 2_4_x内核信号量机制


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-11-01   浏览: 112 ::
收藏到网摘: n/a

信号量作为一种同步机制,在每个成熟的现代操作系统的实现过程中,起着不可替代的作用,对于Linux也不例外,在Linux2_4_x下,实现内核信号量机制的代码虽然不长,但由于涉及到多个进程间的相互干扰,并且在Linux发展过程中,不断进行优化,所以非常难于理解,在讲解Linux源代码的各类文章中,也大都对此语焉不详,本人通过认真阅读,对这部分代码有了一定的了解,这里介绍出来,希望对大家有所帮助。
信号量作为一种同步机制,在每个成熟的现代操作系统的实现过程中,起着不可替代的作用,对于Linux也不例外,在Linux2_4_x下,实现内核信号量机制的代码虽然不长,但由于涉及到多个进程间的相互干扰,并且在Linux发展过程中,不断进行优化,所以非常难于理解,在讲解Linux源代码的各类文章中,也大都对此语焉不详,本人通过认真阅读,对这部分代码有了一定的了解,这里介绍出来,希望对大家有所帮助。 首先看看信号量的概念: 1.信号量的类型定义: 每个信号量至少须记录两个信息:信号量的值和等待该信号量的进程队列。它的类型定义如下:(用类PASCAL语言表述) semaphore = record value: integer; queue: ^PCB; end; 其中PCB是进程控制块,是操作系统为每个进程建立的数据结构。s.value>=0时,s.queue为空; s.value<0时,s.value的绝对值为s.queue中等待进程的个数; 2.PV原语: 对一个信号量变量可以进行两种原语操作:p操作和v操作,定义如下: procedure p(var s:samephore); { s.value=s.value-1; if (s.value<0) asleep(s.queue); } procedure v(var s:samephore); { s.value=s.value+1; if (s.value<=0) wakeup(s.queue); } 其中用到两个标准过程: asleep(s.queue);执行此操作的进程的PCB进入s.queue尾部,进程变成等待状态wakeup(s.queue);将s.queue头进程唤醒插入就绪队列。s.value初值为1时,可以用来实现进程的互斥。p操作和v操作是不可中断的程序段,称为原语。如果将信号量看作共享变量,则pv操作为其临界区,多个进程不能同时执行,一般用硬件方法保证。一个信号量只能置一次初值,以后只能对之进行p操作或v操作。 再来看看在对应的Linux2.4.x具体实现中,信号量的数据结构: struct semaphore { atomic_t count; int sleepers; wait_queue_head_t wait; };可以看到相对于操作系统原理中的定义,数据结构多了一个sleepers成员,这个变量是为使主要分支代码执行速度更快,所作的优化。 其中,count相当于资源计数,为正数或0时表示可用资源数,-1则表示没有空闲资源且有等待进程,而其他的负数仅仅一个中间过程,当所有进程都稳定下来后,将最终变为-1。 sleepers相当于一个状态标志,它仅有0和1两个值,有时会出现2,但也只是中间状态,并没有实际意义。当sleepers为0时,表示没有进程在等待,或等待中的这些进程正在被唤醒过程中。当sleepers为1时,表示至少有一个进程在等待中 wait是等待队列。 在这里可以看到,等待进程的数量并不被关心。 下面我们来看函数,Linux2.4.x具体实现中,down()函数相当于p操作,up()函数相当于v操作。在down()函数中,count做原子减1操作,如果结果不小于0[第4行],则表示成功申请,从down()中返回,如果结果为负(大多数情况是-1,注意判断“结果不小于0”的原因,是因为结果有可能是其他负数),表示需要等待,则调用__down_fail()[第7行],(include/asm-i386/semaphore.h):static inline void down(struct semaphore * sem){1 __asm__ __volatile__(2 # atomic down operation\n\t"3 LOCK "decl %0\n\t" /* --sem->count */4 "js 2f\n"5 "1:\n"6 ".section .text.lock,\"ax\"\n"7 "2:\tcall __down_failed\n\t"8 "jmp 1b\n"9 ".previous"10 :"=m" (sem->count)11 :"c" (sem)12 :"memory");}__down_fail()调用__down(),(arch/i386/kernel/semaphore.c):asm(".text\n"".align 4\n"".globl __down_failed\n""__down_failed:\n\t"13 "pushl %eax\n\t"14 "pushl %edx\n\t"15 "pushl %ecx\n\t"16 "call __down\n\t"17 "popl %ecx\n\t"18 "popl %edx\n\t"19 "popl %eax\n\t"20 "ret");__down()用C代码实现。(arch/i386/kernel/semaphore.c):void __down(struct semaphore * sem){21 struct task_struct *tsk = current;22 DECLARE_WAITQUEUE(wait, tsk);23 tsk->state = TASK_UNINTERRUPTIBLE;24 add_wait_queue_exclusive(&sem->wait, &wait);2526 spin_lock_irq(&semaphore_lock);27 sem->sleepers++;28 for (;;) {29 int sleepers = sem->sleepers;3031 /*32 * Add "everybody else" into it. They aren't33 * playing, because we own the spinlock.34 */35 if (!atomic_add_negative(sleepers - 1, &sem->count)) {36 sem->sleepers = 0;37 break;38 }39 sem->slee