实验五 System V进程间通信

发布时间:2024年01月08日

一、实验目的与任务

目的:了解掌握操作系统消息队列、信号量的特点与功能,学会借助消息队列、信号量的功能函数进行编程。

任务:利用C语言指令编写程序调用消息队列、信号量函数,完成相应功能。

二、实验设备

装有Linux操作系统的计算机一台。

三、实验要求

1、实验内容与要求:

1)利用消息队列、信号量进行进程间的通信

2)利用共享内存进行进程间的数据共享。

2、实验安排方式:采用1人1组,上机在Linux系统下进行编程实验。

四、实验内容

1.创建2个进程,使用消息队列方式实现进程间通信,通信内容为自己姓名和学号。


msgsend.c

msgrcv.c

msgsend.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <sys/msg.h>

#define MAX_TEXT 512

struct my_msg_st {
    long int my_msg_type;
    char some_text[MAX_TEXT];
};

int main()
{
    int running = 1;
    struct my_msg_st some_data;
    int msgid;
    char buffer[BUFSIZ];

    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);

    if (msgid == -1) {
        fprintf(stderr, "msgget failed with error: %d\n", errno);
        exit(EXIT_FAILURE);
    }

    while(running) {
        printf("Enter some text: ");
        fgets(buffer, BUFSIZ, stdin);
        some_data.my_msg_type = 1;
        strcpy(some_data.some_text, buffer);

        if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
            fprintf(stderr, "msgsnd failed\n");
            exit(EXIT_FAILURE);
        }
        if (strncmp(buffer, "end", 3) == 0) 
            running = 0;
     }

    exit(EXIT_SUCCESS);
}

msgrcv.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <sys/msg.h>



struct my_msg_st {
    long int my_msg_type;
    char some_text[BUFSIZ];
};

int main()
{
    int running = 1;
    int msgid;
    struct my_msg_st some_data;
    long int msg_to_receive = 0;
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if (msgid == -1) {
        fprintf(stderr, "msgget failed with error: %d\n", errno);
        exit(EXIT_FAILURE);
    }
    while(running) {
        if (msgrcv(msgid, (void *)&some_data, BUFSIZ,msg_to_receive, 0) == -1) {
            fprintf(stderr, "msgrcv failed with error: %d\n", errno);
            exit(EXIT_FAILURE);
        }
        printf("You wrote: %s", some_data.some_text);
        if (strncmp(some_data.some_text, "end", 3) == 0)
            running = 0;
    }

    if (msgctl(msgid, IPC_RMID, 0) == -1) {
        fprintf(stderr, "msgctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

2.创建2个进程,使用共享内存方式实现进程间通信,通信内容为自己姓名和学号。
shm_w.c

shm_r.c

shm_w.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include <sys/wait.h>
//指定信号量的KEY
#define IPC_KEY 0x12345678 
 
int main()
{
    //1.创建共享内存
    int shmid = shmget(IPC_KEY,512,IPC_CREAT|0777);
    if(shmid<0)
    {
        perror("shmget error");
        exit(1);
    }
    printf("success get sharememory\n");
    //2.将共享内存连接到虚拟内存空间
    void *shm_ptr = shmat(shmid,0,0);   //设置addr为0,让内核选择虚拟地址空间中的第一个可用地址
    if(shm_ptr == (void *)-1)
    {
        perror("shmat error");
        exit(2);
    }
    //3.往共享内存写入数据
    while(1)
    {
        printf(">");
        fflush(stdout);
        scanf("%s",(char *)shm_ptr);
    }
    //4.解除进程与共享内存连接
    shmdt(shm_ptr);
    //5.删除共享内存
    shmctl(shmid,IPC_RMID,NULL);
    return 0;
}       

shm_r.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<sys/wait.h>
#include<string.h>
//指定信号量的KEY
#define IPC_KEY 0x12345678 
 
int main()
{
    //1.获取共享内存标识符
    int shmid = shmget(IPC_KEY,0,0777);
    if(shmid<0)
    {
        perror("shmget error");
        exit(1);
    }
    printf("success get sharememory\n");
    //2.将共享内存连接到虚拟内存空间
    void *shm_ptr = shmat(shmid,0,0);   //设置addr为0,让你内核选择虚拟地址空间中的第一个可用地址
    if(shm_ptr == (void *)-1)
    {
        perror("shmat error");
        exit(2);
    }
    //3.从共享内存读出数据
    while(1)
    {
        if(strlen((char *)shm_ptr))
        {
            printf("read: %s\n",(char *)shm_ptr);
            memset(shm_ptr,0x00,512);  //清理内存
        }
        sleep(1);
    }
    //4.解除进程与共享内存连接
    shmdt(shm_ptr);
    //5.删除共享内存
    shmctl(shmid,IPC_RMID,NULL);
    return 0;
}

3.理发店里有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。如果没有顾客,理发师在理发椅上睡觉。一个顾客来到时,叫醒理发师,如果理发师正在理发时有顾客到来,则如果有空椅子可以坐,就坐下来等待,否则离开。利用信号量的P,V操作来协调理发师、理发椅和顾客之间的活动。

#include <semaphore.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <iostream>
#include <queue>

using namespace std;

typedef sem_t semaphore;
queue<int> wait_queue;

#define CHAIRS 5
int waiting = 0;

semaphore barber;
semaphore consumers;
semaphore mutexlock;

void* barber_process(void*)
{
   while(1)
   {
       int id;
       sem_wait(&consumers);
       sem_wait(&mutexlock);
       waiting = waiting - 1;
       id = wait_queue.front();
       wait_queue.pop();
       sem_post(&barber);
       sem_post(&mutexlock);
       cout << "理发师正在给第" << id << "位等待的顾客理发" << endl; 
       srand(time(0));
       /* sleep(rand() % 3 + 2); */
       sleep(3);
   }
}

void* consumer_process(void* p)
{
    int i = *(int*)p;
    sem_wait(&mutexlock);
    if(waiting < CHAIRS)
    {
        wait_queue.push(i);
        waiting = waiting + 1;
        sem_post(&consumers);
        sem_post(&mutexlock);
        sem_wait(&barber);
        cout << "第" << i << "位顾客来了,正在接受理发师的理发服务" << endl;
        cout << "正在等待理发师理发的顾客还有" << waiting << "位" << endl << endl;
    }
    else
    {
        sem_post(&mutexlock);
        cout << "门外的第" << i << "位顾客看见没有椅子就转身走了" << endl << endl;
    }

    pthread_exit(0);
}

int main()
{
    pthread_t p_barber;
    pthread_t p_consumers[10];

    int num_consumers = 20;

    sem_init(&barber, 0 ,0);
    sem_init(&consumers, 0, 0);
    sem_init(&mutexlock, 0, 1);

    pthread_create(&p_barber, nullptr, barber_process, nullptr);
    
    for(int i = 0; i < num_consumers; i++)
    {
        pthread_create(&p_consumers[i], nullptr, consumer_process, &i);
        srand(time(0));
        sleep(rand() % 2 + 1);
    }

    for(int i = 0; i < num_consumers; i++)
    {
        pthread_join(p_consumers[i], nullptr);
    }

    sleep(5);

    return 0;
}

五、分析总结

通过本次实验,我学会了使用System V IP机制来实现进程之间的通信和同步。首先,我了解了System V IPC机制的基本概念和原理。System V IPC包括三种不同的机制:消息队列、共享内存和信号量。每一种机制都有其独特的特点和用途,可以满足不同的进程间通信需求。例如,消息队列机制可以实现基于消息传递的进程间通信,共享内存机制可以实现高效的共享数据,而信号量机制可以实现进程之间的同步和互斥。其次,我掌握了System V IPC机制的具体应用方法。在实验中,我们需要编写C语言程序,通过调用相关的API函数来创建和管理IPC对象。例如,我们需要使用msgget函数来创建消息队列对象,使用msgsnd和msgrcv函数来发送和接收消息。除此之外,我们还需要了解如何使用信号量来进行进程同步和互斥。

通过这个实验,我不仅学到了技术方面的知识,还提高了我的沟通和团队合作能力。在实验中,我们需要与团队成员共同完成任务,并协调各自的工作。通过与他人合作,我学会了倾听和尊重他人的意见,同时也学会了有效地表达自己的想法和观点。总之,这次实验是一次非常有价值的学习经历。通过实践和探索,我深入了解了进程间通信的原理和技术,并提高了我的编程能力和团队合作能力。这些经验将对我今后的学习和职业发展产生重要的影响,使我更加有信心面对未来的挑战。

文章来源:https://blog.csdn.net/qq_61175638/article/details/135420043
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。