记录以下实践项目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;
}