操作系统实验-水果问题-线程 (Linux平台, 实现语言C/C++。)

本文详细描述了一个使用共享内存和信号量的示例,以解决父亲、女儿和儿子进程间对共享果盘操作的同步问题,通过P和V操作确保数据一致性。程序随机选择进程执行操作,展示进程间协调与通信的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、题目

1.题目

2.目的

3.思路

二、具体实现

1.共享内存结构体定义:

2.信号量操作函数P和V的定义: 

3.father函数的功能

三、运行结果及分析 

1.分析

 2.运行结果


一、题目

1.题目

  实现父亲、女儿、儿子之间的同步。 桌上有个能盛得下5个水果的空盘子, 父亲不停地向盘中放苹果或桔子, 儿子不停地从盘中取桔子享用, 女儿不停地从盘中取苹果享用, 规定三人不能同时从盘子中取放水果。

2.目的

  用简单的例子实现进程间的同步和通信。

3.思路

  通过共享内存,不同的进程可以访问和修改同一份数据。通过信号量,进程可以协调它们的访问,确保数据的一致性和正确性。例如,father函数中的P操作确保在修改共享内存之前,没有其他进程也在修改它;V操作则确保修改完成后,其他等待的进程可以继续执行。

二、具体实现

  注意:完整的程序需要包括信号量的创建、共享内存的分配和连接、以及其他可能涉及的进程创建和同步操作。下面从三个比较重要的部分来分析:共享内存结构体定义、信号量操作函数P和V的定义、以及father函数的功能。

1.共享内存结构体定义:
  •   首先定义一个名为shared_memory的结构体,用于在进程间共享数据。该结构体包含三个整型变量:apple、orange和num,分别用于记录苹果的数量、桔子的数量和总水果数量。
#define SHM_SIZE 1024  
struct shared_memory {  
    int apple;  
    int orange;  
    int num;  
};
2.信号量操作函数P和V的定义: 
  •   定义了用于操作信号量的函数:P操作和V操作。
  • P操作用于申请资源,将信号量的值减1。如果信号量的值为0,则调用进程将进入睡眠状态,直到信号量的值大于0。
  • V操作用于释放资源,将信号量的值加1。如果有其他进程在等待该信号量,则其中一个进程将被唤醒。
void P(int semid) {  
    struct sembuf sem;  
    sem.sem_num = 0;  
    sem.sem_op = -1;  
    sem.sem_flg = SEM_UNDO;  
    semop(semid, &sem, 1);  
}  
  
void V(int semid) {  
    struct sembuf sem;  
    sem.sem_num = 0;  
    sem.sem_op = 1;  
    sem.sem_flg = SEM_UNDO;  
    semop(semid, &sem, 1);  
}
3.father函数的功能
  •   father函数是进程的一部分,用于模拟爸爸往一个共享的果盘里放入水果。
  • 在函数开始,首先执行P操作,申请资源(即信号量)。如果果盘里的水果数量少于5个,则随机决定放入一个苹果或桔子,并更新共享内存中的相应值。然后,释放资源,执行V操作。
void father(int semid, struct shared_memory *shm) {  
    P(semid);  
    if (shm->num < 5) {  
        int b = rand() % 2;  
        if (b == 0) {  
            shm->apple++;  
            shm->num++;  
            printf("爸爸放入一个苹果,现在盆子里有%d 个水果,其中苹果有%d 个,桔子有%d 个\n", shm->num, shm->apple, shm->orange);  
        } else {  
            shm->orange++;  
            shm->num++;  
            printf("爸爸放入一个桔子,现在盆子里有%d 个水果,其中苹果有%d 个,桔子有%d 个\n", shm->num, shm->apple, shm->orange);  
        }  
    }  
    V(semid);  
}

三、运行结果及分析 

1.分析
  • 其中,父进程负责向共享内存中放入水果,而女儿和儿子进程则负责从共享内存中取出水果。

  • 程序会要求用户输入运行次数,这个次数决定了本程序会进行多少次进程操作。

  • 在每次循环中,会随机选择一个进程进行操作。具体的操作由father、daughter和son三个函数实现,分别对应父进程、女儿进程和儿子进程。

  • 在每次操作后,程序会打印出当前共享内存中水果的数量和分布情况。最后,程序会删除共享内存和信号量。因为是随机选择进程进行操作,因此每次运行的结果都不一样。

 2.运行结果
  • 运行次数5

  • 运行次数10

四、源码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHM_SIZE 1024
typedef int semaphore;
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};
struct shared_memory {
    int apple;
    int orange;
    int num;
};
void P(int semid) {
    struct sembuf sem;
    sem.sem_num = 0;
    sem.sem_op = -1;
    sem.sem_flg = SEM_UNDO;
    semop(semid, &sem, 1);
}
void V(int semid) {
    struct sembuf sem;
    sem.sem_num = 0;
    sem.sem_op = 1;
    sem.sem_flg = SEM_UNDO;
    semop(semid, &sem, 1);
}
void father(int semid, struct shared_memory *shm) {
    P(semid);
    if (shm->num < 5) {
        int b = rand() % 2;
        if (b == 0) {
            shm->apple++;
            shm->num++;
            printf("爸爸放入一个苹果,现在盆子里有%d个水果,其中苹果有%d个,桔子有%d个\n", shm->num, shm->apple, shm->orange);
        } else {
            shm->orange++;
            shm->num++;
            printf("爸爸放入一个桔子,现在盆子里有%d个水果,其中苹果有%d个,桔子有%d个\n", shm->num, shm->apple, shm->orange);
        }
    } else {
        printf("爸爸操作失败,盆子里已经有5个水果,其中有%d个苹果,%d个桔子\n", shm->apple, shm->orange);
    }
    V(semid);
}
void daughter(int semid, struct shared_memory *shm) {
    P(semid);
    if (shm->apple > 0) {
        shm->apple--;
        shm->num--;
        printf("女儿拿了一个苹果,盆子里还有%d个水果,其中苹果有%d个,桔子有%d个\n", shm->num, shm->apple, shm->orange);
    } else {
        printf("女儿拿取失败,盆子里有%d个水果,其中苹果有%d个,桔子有%d个\n", shm->num, shm->apple, shm->orange);
    }
    V(semid);
}
void son(int semid, struct shared_memory *shm) {
    P(semid);
    if (shm->orange > 0) {
        shm->orange--;
        shm->num--;
        printf("儿子拿了一个桔子,盆子里还有%d个水果,其中苹果有%d个,桔子有%d个\n", shm->num, shm->apple, shm->orange);
    } else {
        printf("儿子拿取失败,盆子里有%d个水果,其中苹果有%d个,桔子有%d个\n", shm->num, shm->apple, shm->orange);
    }
    V(semid);
}
int main() {
    int n, a;
    int shmid, semid;
    struct shared_memory *shm;
    union semun semarg;
    // 创建共享内存
    shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }
    // 连接共享内存
    shm = (struct shared_memory *) shmat(shmid, NULL, 0);
    if (shm == (struct shared_memory *) -1) {
        perror("shmat");
        exit(1);
    }
    // 初始化共享内存
    shm->apple = 0;
    shm->orange = 0;
    shm->num = 0;
    // 创建信号量
    semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("semget");
        exit(1);
    }
    // 初始化信号量
    semarg.val = 1;
    if (semctl(semid, 0, SETVAL, semarg) == -1) {
        perror("semctl");
        exit(1);
    }
    printf("请输入你要运行的次数:");
    scanf("%d", &n);
    while (n--) {
        a = rand() % 3;
        if (a == 0) {
            printf("爸爸进行操作\n");
            father(semid, shm);
            printf("\n");
        } else if (a == 1) {
            printf("女儿进行操作\n");
            daughter(semid, shm);
            printf("\n");
        } else {
            printf("儿子进行操作\n");
            son(semid, shm);
            printf("\n");
        }
    }
    // 删除信号量
    if (semctl(semid, 0, IPC_RMID, semarg) == -1) {
        perror("semctl");
        exit(1);
    }
    // 分离共享内存
    if (shmdt(shm) == -1) {
        perror("shmdt");
        exit(1);
    }
    // 删除共享内存
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        exit(1);
    }
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值