操作系统第6次实验报告:使用信号量解决进程互斥访问

  • 姓名:朱笃信
  • 学号:201821121021
  • 班级:计算1811

1. 选择哪一个问题

  • 哲学家进餐问题

2. 给出伪代码

semid<-semget创建信号量
for i :=0 to 5
begin
semctl将信号量初始化为1
end
for i :=0 to 5
begin
fork()
end
打印:哲学家在思考
sleep()
打印:哲学家饿了
P()更改信号量的值为-1
打印:哲学家在吃饭
sleep()
V()更改信号量的值为1

3. 给出完整代码

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/wait.h>

#define Wait (rand() % 5 + 1)

union semun {
        int val;                        /* value for SETVAL */
        struct semid_ds *buf;           /* buffer for IPC_STAT, IPC_SET */
        unsigned short int *array;      /* array for GETALL, SETALL */
        struct seminfo *__buf;          /* buffer for IPC_INFO */
};

void P(int semid,int no);		//P操作,
void V(int semid,int no);			//V操作
void philosoper(int semid,int no);			//哲学家

int main(void)
{

    int semid = semget(IPC_PRIVATE, 5, IPC_CREAT | 0666);//创建一个新信号量或取得一个已有信号量
    if (semid == -1)		//失败,进行报错
        printf("semget error.\n");
    union semun sm;
    sm.val = 1;
    int i;
    for (i = 0; i < 5; i++)
    {
        semctl(semid, i, SETVAL, sm);		//直接控制信号量信息
    }

    int no = 0;
    pid_t pid;
    for (i = 1; i < 5; i++)
    {
        pid = fork();
        if (pid == -1)
            printf("fork error.\n");
        if (pid == 0)
        {
            no = i;
            break;
        }
    }
    philosoper(semid,no);
    return 0;
}

void philosoper(int semid,int no)
{
    srand(getpid());
    while(1)
    {

        printf("第%d位哲学家在思考\n", no);
        sleep(Wait);
        printf("第%d位哲学家饿了\n", no);
        P(semid,no);
        printf("第%d位哲学家在吃饭\n", no);
        sleep(Wait);
        V(semid,no);
    }
}


void P(int semid,int no)
{
    int left = no;
    int right = (no + 1) % 5;

    struct sembuf buf[2] ={{left, -1, 0},{right, -1, 0}};

    if(semop(semid, buf, 2) == -1) {
        printf("P error.\n");
        exit(1);
    }
}

void V(int semid,int no)
{
    int left = no;
    int right = (no + 1) % 5;

    struct sembuf buf[2] ={{left, 1, 0},{right, 1, 0}};

    if(semop(semid, buf, 2) == -1) {
        printf("V error.\n");
        exit(1);
    }
}

该代码中包含几个库函数:

1.int semget(key_t key, int num_sems, int sem_flags);

第一个参数key是整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget()函数并提供一个键,再由系统生成一个相应的信号标识符(semget()函数的返回值),只有semget()函数才直接使用信号量键,所有其他的信号量函数使用由semget()函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作。

第二个参数num_sems指定需要的信号量数目,它的值几乎总是1。

第三个参数sem_flags是一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

semget()函数成功返回一个相应信号标识符(非零),失败返回-1。

2.int semctl(int sem_id, int sem_num, int command, ...);

前两个参数与前面一个函数中的一样,command通常是下面两个值中的其中一个

SETVAL:用来把信号量初始化为一个已知的值。p 这个值通过union semun中的val成员设置,其作用是在信号量第一次使用前对它进行设置。

IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。

3.int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

改变信号量的值

4. 运行结果并解释

操作系统第6次实验报告:使用信号量解决进程互斥访问

 

操作系统第6次实验报告:使用信号量解决进程互斥访问

 

 

 程序开始先创建进程,分别对应五个哲学家,哲学家们首先进入思考状态,首先是第二位哲学家饿了,成了第一个吃螃蟹的人,他拿起了第一跟第二根筷子,然后第0位哲学家饿了,他拿起了0与4的筷子,第二位哲学家吃完了,又开始思考,此时第一与第二根筷子可以用了,第三位哲学家饿了,拿起第二与第三根筷子,第四位哲学家也饿了,但是他没有筷子可以用,第一位哲学家也饿了,但是他也缺个筷子,第0号哲学家吃好了,第一位哲学家拿到筷子,开始吃饭。

上一篇:PCB的IPC标准是什么


下一篇:并发控制:进程通信之消息队列