当前位置:  技术问答>linux和unix

一家公司的面试题目,求解!

    来源: 互联网  发布时间:2015-08-18

    本文导语:  假如一个阅览室最多可容纳N个人,读者进入和离开阅览室时,都必须在每次只允许一个人写的登记表上做进入登记和离开登记,试用P、V操作实现读者间的协调关系。 | [转帖] POSIX有信号量,S...

假如一个阅览室最多可容纳N个人,读者进入和离开阅览室时,都必须在每次只允许一个人写的登记表上做进入登记和离开登记,试用P、V操作实现读者间的协调关系。

|
[转帖]
POSIX有信号量,SysV IPC有信号量,核内也有信号量,接口很简单,一个down(),一个up(),分别对应P操作和V操作,down()调用可能引起线程挂起,因此和sleep_on类似,也有interruptible系列接口。down意味着信号量减1,up意味着信号量加1,这两个操作显然需要互斥。在Linux 2.4中,并没有如想象中的用锁实现,而是使用了原子操作。
在include/asm/atomic.h中定义了一系列原子操作,包括原子读、原子写、原子加等等,大多是直接用汇编语句来实现的,这里就不详细解释。
我们从信号量数据结构开始,它定义在include/asm/semaphore.h中:
struct semaphore {
        atomic_t count;
        int sleepers;
        wait_queue_head_t wait;
}
  
down()操作可以理解为申请资源,up()操作可以理解为释放资源,因此,信号量实际表示的是资源的数量以及是否有进程正在等待。在semaphore结构中,count相当于资源计数,为正数或0时表示可用资源数,-1则表示没有空闲资源且有等待进程。而等待进程的数量并不关心。这种设计主要是考虑与信号量的原语相一致,当某个进程执行up()函数释放资源,点亮信号灯时,如果count恢复到0,则表示尚有进程在等待该资源,因此执行唤醒操作。一个典型的down()-up()流程是这样的:
down()-->count做原子减1操作,如果结果不小于0则表示成功申请,从down()中返回;
-->如果结果为负(实际上只可能是-1),则表示需要等待,则调用__down_fail();
__down_fail()调用__down(),__down()用C代码实现,要求已不如down()和__down_fail()严格,在此作实际的等待(arch/i386/kernel/semaphore.c):
void __down(struct semaphore * sem)
{
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
        tsk->state = TASK_UNINTERRUPTIBLE;
        add_wait_queue_exclusive(&sem->wait, &wait);

        spin_lock_irq(&semaphore_lock);
        sem->sleepers++;
        for (;;) {
                int sleepers = sem->sleepers;

                /*
                 * Add "everybody else" into it. They aren't
                 * playing, because we own the spinlock.
                 */
                if (!atomic_add_negative(sleepers - 1, &sem->count)) {
                        sem->sleepers = 0;
                        break;
                }
                sem->sleepers = 1;      /* us - see -1 above */
                spin_unlock_irq(&semaphore_lock);

                schedule();
                tsk->state = TASK_UNINTERRUPTIBLE;
                spin_lock_irq(&semaphore_lock);
        }
        spin_unlock_irq(&semaphore_lock);
        remove_wait_queue(&sem->wait, &wait);
        tsk->state = TASK_RUNNING;
        wake_up(&sem->wait);
}
   
__down()-->当前进程进入wait等待队列,状态为不可中断的挂起,sleepers++,如果这是第一次申请失败,则sleepers值为1,否则为2--这个设置纯粹是为了下面这句原子加而安排的。
在真正进入休眠以前,__down()还是需要判断一下是不是确实没有资源可用,因为在spin_lock之前什么都可能发生。atomic_add_negative()将sleepers-1(只可能是0或者1,分别表示仅有一个等待进程或是多个)加到count(如果有多个进程申请资源失败进入__down(),count可能为-2、-3等)之上,这个加法完成后,结果为0只可能是在sleepers等于1的时候发生(因为如果sleepers等于2,表示有多个进程执行了down(),则count必然小于-1,因此sleepers-1+count必然小于0),表示count在此之前已经变为0了,也就是说已经有进程释放了资源,因此本进程不用休眠而是获得资源退出__down(),从而也从down()中返回;如果没有进程释放资源,那么在所有等待进程的这一加法完成后,count将等于-1。因此,从down()调用外面看(无论是在down()中休眠还是获得资源离开down()),count为负时只可能为-1(此时sleepers等于1),这么设计使得up()操作只需要对count加1,判断是否为0就可以知道是否有必要执行唤醒操作__up_wakeup()了。
获得了资源的进程将把sleepers设为0,并唤醒所有其他等待进程,这个操作实际上只是起到恢复count为-1,并使它们再次进入休眠的作用,因为第一个被唤醒的等待进程执行atomic_add_negative()操作后会将count恢复为-1,然后将sleepers置为1;以后的等待进程则会像往常一样重新休眠。
将down()操作设计得如此复杂的原因和结果就是up操作相当简单。up()利用汇编原子地将count加1,如果小于等于0表示有等待进程,则调用__up_wakeup()-->__up()唤醒wait;否则直接返回。
在down()中竞争获得资源的进程并不是按照优先级排序的,只是在up()操作完成后第一个被唤醒或者正在__down()中运行而暂未进入休眠的进程成功的可能性稍高一些。
尽管可以将信号量的count初始化为1从而实现一种互斥锁(mutex),但Linux并不保证这个count不会超过1,因为up操作并不考虑count的初值,所以只能依靠程序员自己来控制不要无谓的执行up()从而破坏mutex的语义。相关的初始化接口定义在include/asm/semaphore.h中,但一般程序员可以通过sema_init()接口来初始化信号量:
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
static inline void sema_init (struct semaphore *sem, int val)
static inline void init_MUTEX (struct semaphore *sem)
static inline void init_MUTEX_LOCKED (struct semaphore *sem)
   
除了down()以外,Linux还提供了一个down_interruptible(),操作序列与down()基本相同,仅在休眠状态为可中断和信号处理上有所不同。在标准的信号量以外,还有一套读写信号量,用于将资源的读写区分开来进行同步以提高效率,采用读写锁来实现,有兴趣的可以参阅文后列出的参考资料。

|
设s1=1,表示登记进入人数;s2=2,表示登记离开人数;s3=n,总共可容纳人数。
进入:
in()
{
p(s3);
p(s1);
...(其他操作)
v(s1);
}
out()
{
v(s3);
p(s2);
...(其他操作)
v(s2);
}

|
在in的函数中用对人数100进行p操作,对登记进行p操作,对登记进行v操作;在out函数中对人数进行v操作,对登记进行p操作,对登记进行v操作。

|
http://community.csdn.net/Expert/topic/3403/3403031.xml?temp=.703274

    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 一家月薪上万的外企的面试题(Linux C工程師)
  • 我这里有个 国内一家知名公司开发的erp软件, 我有原码,谁要?
  • 清问有没有人听说过沈阳的一家公司出了一款redhat下的中文kde环境,如果知道清帮忙告诉我哪里能找到,谢谢!
  • 呵呵,今天换了一家新地方,感觉比较满意,散分。(内空)
  • 这是一家什么公司(上海朋友请进) iis7站长之家
  • 大家认为国产Linux好不好,和国外有什么差距!国产Linux哪一家的比较好点?
  • Oracle和Redhat的offer,我该选择那一家,请给点意见。
  • 呵呵,今天换了一家新地方,感觉比较满意,散分(2)
  • 这是一家什么公司(上海朋友请进)
  • 小弟想跳到一家大公司搞JAVA开发,但是要先做技术支持一类的工作,经常出差,而且不知道何时才能真正搞开发?该去还是该留?
  • 小弟明天去一家挺好的公司,我LINUX书还没看完,心里没底,放分大家给我加油,祝我成功!
  • 小弟现在想到一家公司应聘,可是人家说要精通TCP/IP, 我有两个月的时间,如何精通啊? :)


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3