信号量的实现和应用.doc
文本预览下载声明
信号量的实现和应用
难度系数:☆
实验目的
加深对进程同步与互斥概念的认识;
掌握信号量的使用,并应用它解决生产者——消费者问题;
掌握信号量的实现原理。
实验内容
本次实验的基本内容是:
在Ubuntu下编写程序,用信号量解决生产者——消费者问题;
在0.11中实现信号量,用生产者—消费者程序检验之。
用信号量解决生产者—消费者问题
在Ubuntu上编写应用程序“pc.c”,解决经典的生产者—消费者问题,完成下面的功能:
建立一个生产者进程,N个消费者进程(N1);
用文件建立一个共享缓冲区;
生产者进程依次向缓冲区写入整数0,1,2,...,M,M=500;
消费者进程从缓冲区读数,每次读一个,并将读出的数字从缓冲区删除,然后将本进程ID和数字输出到标准输出;
缓冲区同时最多只能保存10个数。
一种可能的输出效果是:
10: 010: 110: 210: 310: 411: 511: 612: 710: 812: 912: 1012: 1112: 12……11: 49811: 499
其中ID的顺序会有较大变化,但冒号后的数字一定是从0开始递增加一的。
pc.c中将会用到sem_open()、sem_close()、sem_wait()和sem_post()等信号量相关的系统调用,请查阅相关文档。
《UNIX环境高级编程》是一本关于Unix/Linux系统级编程的相当经典的教程。校园网用户可以在/study/Computer_Science/Linux_Unix/?下载,后续实验也用得到。如果你对POSIX编程感兴趣,建议买一本常备手边。
实现信号量
Linux在0.11版还没有实现信号量,Linus把这件富有挑战的工作留给了你。如果能实现一套山寨版的完全符合POSIX规范的信号量,无疑是很有成就感的。但时间暂时不允许我们这么做,所以先弄一套缩水版的类POSIX信号量,它的函数原型和标准并不完全相同,而且只包含如下系统调用:
/man/7/sem_overviewusg=AFQjCNGsL7S0Ey7Ri6QFze-4ss4oBWTQxg符合POSIX规范的信号量,无疑是很有成就感的。但时间暂时不允许我们这么做,所以先弄一套缩水版的类POSIX信号量,它的函数原型和标准并不完全相同,而且只包含如下系统调用:
sem_t *sem_open(const char *name, unsigned int value);int sem_wait(sem_t *sem);int sem_post(sem_t *sem);int sem_unlink(const char *name);
sem_t是信号量类型,根据实现的需要自定义。
sem_open()的功能是创建一个信号量,或打开一个已经存在的信号量。
name是信号量的名字。不同的进程可以通过提供同样的name而共享同一个信号量。如果该信号量不存在,就创建新的名为name的信号量;如果存在,就打开已经存在的名为name的信号量。
value是信号量的初值,仅当新建信号量时,此参数才有效,其余情况下它被忽略。
当成功时,返回值是该信号量的唯一标识(比如,在内核的地址、ID等),由另两个系统调用使用。如失败,返回值是NULL。
sem_wait()就是信号量的P原子操作。如果继续运行的条件不满足,则令调用进程等待在信号量sem上。返回0表示成功,返回-1表示失败。
sem_post()就是信号量的V原子操作。如果有等待sem的进程,它会唤醒其中的一个。返回0表示成功,返回-1表示失败。
sem_unlink()的功能是删除名为name的信号量。返回0表示成功,返回-1表示失败。
在kernel目录下新建“sem.c”文件实现如上功能。然后将pc.c从Ubuntu移植到0.11下,测试自己实现的信号量。
实验报告
完成实验后,在实验报告中回答如下问题:
在pc.c中去掉所有与信号量有关的代码,再运行程序,执行效果有变化吗?为什么会这样?
实验的设计者在第一次编写生产者——消费者程序的时候,是这么做的:
Producer(){ P(Mutex); //互斥信号量 生产一个产品item; P(Empty); //空闲缓存资源 将item放到空闲缓存中; V(Full); //产品资源 V(Mutex);}Consumer(){ P(Mutex); P(Full); 从缓存区取出一个赋值给item; V(Empty); 消费产品item; V(Mutex);}
这样可行吗?如果可行,那么它和标准解法在执行效果上会有什么不同?如果不
显示全部