信号量的实现与应用

记录以下实践项目5:信号量的实现与应用

sem.c:

//只有正数的实现(利用sleep_on)
``int sem_wait(sem_t * sem)
{
    //关中断
    cli();

    //由于V操作已经唤醒了所有进程,并且已经通过shedule()调度了其中优先级最大的进程,
    //然后遍历所有的进程,直到找到value不为0的,也就是获得了信号量的,继续执行
    while(sem->value == 0)
        sleep_on(&(sem->queue));
    sem_value--;
    //开中断
    sti();
    return 0;
}

//这里老师说是链式唤醒,那我觉得链式唤醒全部队列只是一种可能,当然肯定要比下一种方法好一点
int sem_post(sem_t * sem)
{
    //关中断
    cli();
    //判断:如果传入的信号量不满足要求,P操作失败,返回-1
    if(sem < sem_list || sem > sem_list + SEM_LIST_LENGTH)
    {
        sti();
        printk("sem (V) error\n");
        return -1;
    }
    //唤醒阻塞队列队首进程 可出现链式唤醒现象  将阻塞队列上所有的进程全部唤醒
    sem->value++;
    wake_up(&(sem->queue));
    //开中断
    sti();
    return 0;
}

//正负都有的实现(需要自己写队列)
int sem_wait(sem_t * sem)
{
    //关中断
    cli();
    //value--,判断是不是要阻塞
    sem->value--;
    if(sem->value < 0)
    {
       
        current->state = TASK_UNINTERRUPTIBLE;
        //将当前阻塞的进程加入到阻塞队列,这里的队列和对队列的操作都要自己实现
        insert_task(current,&(sem->wait_queue))
        //由于该进程阻塞,所以需要调度下一个进程
        schedule(); 
        //这里我曾经很疑惑调度走了 可中断已经关了怎么办
        //后来想明白了 调度到下一个消费者进程的sem_wait()会执行她的sti() 一样可出去
        
    }
    //开中断
    sti();
    return 0;
}

int sem_post(sem_t * sem)
{
    //关中断
    cli();
    //value++,判断是不是要唤醒
    sem->value++;
    if(sem->value <= 0)
    {
        //value++ <=0,说明要将阻塞队列中的一个进程唤醒(直接取队首的进程,将进程的PCB赋值给p指针)
        //将取出来的进程的状态设置为就绪态,加入到就绪队列
        struct task_struct * p;
        p = get_task(&(sem->wait_queue));
        if(p != NULL)
        {
            p->state = TASK_RUNNING;
        }
        insert_task(p,&(sem->ready_queue));//这句话好像在(from github的代码没有)
    }
}

PC.C:
值得一提的是,为了保证消费者进程的合理有序通信 每读取一次字符,将文件位置写入了缓冲区的一个固定位置(空洞文件)

#define __LIBRARY__

#include <unistd.h> 
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/sem.h>
#include <sys/types.h>
#include <sys/wait.h>

#define BUFSIZE 10 /*缓冲区大小*/
#define NUMBER 500 
#define COSUMER 5


_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);



sem_t *empty, *full,*mutex;


int main()
{
    int fd;
    int  buf_out ; /*从缓冲区读取位置*/
    int  buf_in ; /*写入缓冲区位置*/
    int p; 
    int data;
    int i;
    int k;
    /*打开信号量*/
    fd = open("file.txt", O_CREAT| O_TRUNC| O_RDWR, 777);
    buf_out = 0;
    buf_in = 0;
    
    if((mutex = sem_open("carmutex", 1)) == NULL)
    {
        printf("sem_open() error!\n");
        fflush(stdout);
        return -1;
    }
    if((empty = sem_open("carempty",10)) == NULL)
    {
        printf("sem_open() error!\n");
        fflush(stdout);
        return -1;
    }
    if((full = sem_open("carfull",0)) == NULL)
    {
        printf("sem_open() error!\n");
        fflush(stdout);
        return -1;
    }
    
	/*空洞文件 在固定位置存储buf_out*/
    lseek(fd, BUFSIZE*sizeof(int), SEEK_SET);
    write(fd, (char*)&buf_out, sizeof(int));

    printf("Done1!\n");
    fflush(stdout);

    if(p = fork())
    {
        printf("pid %d:\tproducer created....\n", p);
        fflush(stdout);

        for( i = 0; i < NUMBER;i++)
        {
            sem_wait(empty);
            sem_wait(mutex);
        
            lseek(fd, buf_in*sizeof(int), SEEK_SET);
            write(fd,(char*)&i,sizeof(int));
            printf("producer write %d\n",i);
            fflush(stdout);
      
            buf_in = (buf_in +1)%BUFSIZE;
            sem_post(mutex);
            sem_post(full);
        }
        
        exit(0);

    }
    else 
  
 
    for (i = 0; i < COSUMER; i++)
    {
        if((p = fork()))
        {
            printf("pid %d:\tconsumer %d created....\n", p,i);
            fflush(stdout);
            
            for(k = 0; k < NUMBER/COSUMER;k++)
            {
                sem_wait(full);
                sem_wait(mutex);
 
                
                lseek(fd, BUFSIZE*sizeof(int), 0);
                read(fd, (char *)&buf_out,sizeof(int));
  
                lseek(fd, buf_out*sizeof(int), 0);
                read(fd, (char *)&data, sizeof(int));
                buf_out = (buf_out +1)%BUFSIZE;
                lseek(fd, BUFSIZE*sizeof(int), 0);
                write(fd, (char*)&buf_out, sizeof(int));




                
                printf("consumer %d read %d\n",i,data);
                fflush(stdout);
                sem_post(mutex);
                sem_post(empty);
            }
            exit(0);
        }

    }
    wait(NULL);
    wait(NULL);
    wait(NULL);
    wait(NULL);
    wait(NULL);
    wait(NULL);
    close(fd);
    sem_unlink("carmutex");
    sem_unlink("carempty");
    sem_unlink("carfull");
    return 0;

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值