哈工大OS实验六---信号量的实现和应用

实验步骤参考

原文链接:https://blog.csdn.net/realfancy/article/details/90112982

说明:这个实验我基本都是按着这位博主来做的,虽然出了一点小问题,但是这位博主写的很好,我就再对这里面的代码说明一下吧,大家如果要看完整的步骤,可以去看这位博主的

实验要求:

实现三个函数

  1. sem_open(): 创建一个信号量或者打开一个以及存在的信号量
  2. sem_wait():信号量的P原子操作
  3. sem_post():信号量的V原子操作
  4. sem_unlink():删除名为name的信号量

这几个函数都是系统调用函数,有关系统调用的知识可以看这篇文章系统调用原理

kernel/sem.c目录下实现这几个函数,我们具体看一下代码

sem_t *sys_sem_open(const char *name,unsigned int value)
{
    char kernelname[100];   
    int isExist = 0;
    int i=0;
    int name_cnt=0;
    while( get_fs_byte(name+name_cnt) != '\0') //get_fs_byte的作用为,在传递进///来的地址处取出一个字节
    name_cnt++;
    if(name_cnt>SEM_NAME_LEN)  //如果信号量的名字大于SEM_NAME_LEN,就返回NULL
    return NULL;
    for(i=0;i

编写pc.c文件

#define __LIBRARY__
#include 
#include 
#include 
#include 
#include 
#include 
#include 

_syscall2(sem_t *,sem_open,const char *,name,unsigned int,value)
_syscall1(int,sem_wait,sem_t *,sem)
_syscall1(int,sem_post,sem_t *,sem)
_syscall1(int,sem_unlink,const char *,name)

const char *FILENAME = "/usr/root/buffer_file";    /* 消费生产的产品存放的缓冲文件的路径 */
const int NR_CONSUMERS = 5;                        /* 消费者的数量 */
const int NR_ITEMS = 50;                        /* 产品的最大量 */
const int BUFFER_SIZE = 10;                        /* 缓冲区大小,表示可同时存在的产品数量 */
sem_t *metux, *full, *empty;                    /* 3个信号量 */
unsigned int item_pro, item_used;                /* 刚生产的产品号;刚消费的产品号 */
int fi, fo;                                        /* 供生产者写入或消费者读取的缓冲文件的句柄 */


int main(int argc, char *argv[])
{
    char *filename;
    int pid;
    int i;

    filename = argc > 1 ? argv[1] : FILENAME;
    /* O_TRUNC 表示:当文件以只读或只写打开时,若文件存在,则将其长度截为0(即清空文件)
    * 0222 和 0444 分别表示文件只写和只读(前面的0是八进制标识)
    */
    fi = open(filename, O_CREAT| O_TRUNC| O_WRONLY, 0222);    /* 以只写方式打开文件给生产者写入产品编号 */
    fo = open(filename, O_TRUNC| O_RDONLY, 0444);            /* 以只读方式打开文件给消费者读出产品编号 */

    metux = sem_open("METUX", 1);    /* 互斥信号量,防止生产消费同时进行 */
    full = sem_open("FULL", 0);        /* 产品剩余信号量,大于0则可消费 */
    empty = sem_open("EMPTY", BUFFER_SIZE);    /* 空信号量,它与产品剩余信号量此消彼长,大于0时生产者才能继续生产 */

    item_pro = 0;

    if ((pid = fork()))    /* 父进程用来执行消费者动作 */
    {
        printf("pid %d:\tproducer created....\n", pid);
        /* printf()输出的信息会先保存到输出缓冲区,并没有马上输出到标准输出(通常为终端控制台)。
        * 为避免偶然因素的影响,我们每次printf()都调用一下stdio.h中的fflush(stdout)
        * 来确保将输出立刻输出到标准输出。
        */
        fflush(stdout);

        while (item_pro <= NR_ITEMS)    /* 生产完所需产品 */
        {
            sem_wait(empty);
            sem_wait(metux);

            /* 生产完一轮产品(文件缓冲区只能容纳BUFFER_SIZE个产品编号)后
            * 将缓冲文件的位置指针重新定位到文件首部。
            */
            if(!(item_pro % BUFFER_SIZE))
                lseek(fi, 0, 0);

            write(fi, (char *) &item_pro, sizeof(item_pro));        /* 写入产品编号 */
            printf("pid %d:\tproduces item %d\n", pid, item_pro);
            fflush(stdout);
            item_pro++;

            sem_post(full);        /* 唤醒消费者进程 */
            sem_post(metux);
        }
    }
    else    /* 子进程来创建消费者 */
    {
        i = NR_CONSUMERS;
        while(i--)
        {
            if(!(pid=fork()))    /* 创建i个消费者进程 */
            {
                pid = getpid();
                printf("pid %d:\tconsumer %d created....\n", pid, NR_CONSUMERS-i);
                fflush(stdout);

                while(1)
                {
                    sem_wait(full);
                    sem_wait(metux);

                    /* read()读到文件末尾时返回0,将文件的位置指针重新定位到文件首部 */
                    if(!read(fo, (char *)&item_used, sizeof(item_used)))
                    {
                        lseek(fo, 0, 0);
                        read(fo, (char *)&item_used, sizeof(item_used));
                    }

                    printf("pid %d:\tconsumer %d consumes item %d\n", pid, NR_CONSUMERS-i+1, item_used);
                    fflush(stdout);

                    sem_post(empty);    /* 唤醒生产者进程 */
                    sem_post(metux);

                    if(item_used == NR_ITEMS)    /* 如果已经消费完最后一个商品,则结束 */
                        goto OK;
                }
            }
        }
    }
OK:
    close(fi);
    close(fo);
    return 0;
}

你可能感兴趣的:(linux,操作系统)