文章 35
评论 44
浏览 106906
杭电操作系统实验三:linux进程管理

杭电操作系统实验三:linux进程管理

dd.jpg

实验三:linux进程管理

1)实现一个模拟的shell

问题:编写三个cmd1.ccmd2.ccmd3.c程序,功能自定。需要一个仿shell的程序和实现类似执行grepfind等命令的程序。通过在仿shell中输入命令(字符串和参数),创建子进程来执行相应的命令程序,父进程需要等待子进程处理结束后,才能再去查看是否有新的命令。输入“exit”退出shell程序。输入无效命令则显示“Command not found”,等待下一个新命令。

前说下,刚开始把问题看复杂了,除了要求之外还写了cdpwdexitmkdir,所以可以自行删改(不麻烦),或者有兴趣可以加更多的命令玩玩 : )

处理方法:

myshell.c:

  • 提供循环输入命令模块
  • 解析命令
  • 判断命令是内置命令还是外置命令(可以不用)
  • 内置命令直接调用函数,外置命令用fork()来创建一个子进程, 在进程中执行命令程序采用exec族的函数来调用函数执行。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/syscall.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#define MAX_BUF 80
#define MAX_CMD 80
#define MAX_ARG_NR 16
int cmd_len;                    //输入的命令长度(包含换行符)
//////////////////////////////////////////////////////////////////////////
int main()
{
    char buf[MAX_BUF];
    char command[MAX_CMD+1];
    system("clear");
    printf("Songshell: support cd/pwd/mkdir/exit/find/grep\n");
    while(1){
        getcwd(buf, sizeof(buf));
        printf("➜ [%s] ", buf);
        fflush(stdout);         //输出上一行内容
        memset(command,0, sizeof(command));
        if((cmd_len = read(0, command, MAX_CMD)) < 2)   //仅有回车,cmd_len=1
            printf("Command Error! Pleace Try Again\n");
        else{
            ToProcess(command);
        }
    }
    return 0;
}

ssize_t read(int fd, void *buf, size_t count);

read(0, command, MAX_CMD))从标准输入文件中读取最大长度为MAX_CMD并带有回车的字符串写入command,当除了回车还有其他字符时,调用ToProcess(command)

//执行命令
int ToProcess(const char *command)
{
    char *argv[MAX_CMD];
    char buf[MAX_CMD];
    strcpy(buf, command);
    buf[cmd_len-1] = ' ';
    buf[cmd_len] = '\n'; 
    ParsePalam(buf, argv);
    if(argv[0] == NULL)     		//命令为空
        return 0;
    if(!JudgeBuildin(argv)){
        //不是内置命令
        pid_t child = fork();
        if(child > 0){
            int status = 0;
            wait(&status);
        }
        else if(child == 0){         //子进程
            if(!strcmp(argv[0], "mkdir"))
                execl("/home/exp3/myshell/mkdir_cmd", argv[1], NULL);
            else if(!strcmp(argv[0], "command1"))
                execl("/home/exp3/myshell/command1", argv[0], NULL);
            else if(!strcmp(argv[0], "command2"))
                execl("/home/exp3/myshell/command2", argv[0], NULL);
            else if(!strcmp(argv[0], "command3"))
                execl("/home/exp3/myshell/command3", argv[0], NULL);
            else if(!strcmp(argv[0], "find"))
                execv("/usr/bin/find",argv);
            else if(!strcmp(argv[0], "grep"))
                execv("/usr/bin/grep", argv);
        }
        else if(child == -1){
            printf("failed: no child process is created!\n");
        }
    }
    return 0;
}

P7-8:为了让后面ParsePalam()函数更好解析输入的命令参数。在最后一个参数的后面添加空格, 和其他参数结构保持一致(这里不加,解析会出错)。

P9:解析完参数,包括命令及参数都按输入顺序存入char *argv[]指针数组中,调用形式为argv[0],argv[1]..

P12:一般而言,在一个脚本里执行一个外部命令(普通的可执行文件)时,shell 会 fork 出一个子进程,然后再用 exec族函数来执行这个程序;但是,bash shell 的内置命令(builtin)却不会这样,它们是直接执行的。所以,等价的内置命令的执行速度会比执行外部命令要来的快。

可以通过type或者which命令来查看命令类型:提到builtin就是内置,打印出目录如/usr/bin/xxxx这样的就是外置命令
image20201203170855621.png

如果不是内置命令就要涉及创建子进程和执行外部程序的实现了

通过终端输入man 2 fork查看fork的编程手册。

P15:child>0,返回的是子进程的PID号,说明当前是父进程,按要求,父进程不需要做什么事,等着就完事了。man 2 wait,看下头文件,函数用最简单的wait(int *wstatus)

P19:child == 0,说明是子进程,于是要调用外部程序了,man exec查看exec族的相关信息。exec族博客
image20201203164609486.png

拿P21的execl("/home/exp3/myshell/mkdir_cmd", argv[1], NULL);举例,execl的参数依次是,调用程序的路径名, 参数0,参数1,.....,NULL结尾。这里的argv[1]就是要创建的目录名

mkdir_cmd.c

#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
    if(mkdir(argv[0], 0755) == -1){
        printf("mkdir failed\n");
    }
    return 0;
}

提醒,main参数一定别忘记了argc,血泪教训,参数就是顺序写入到argv中,我只传入了一个参数。

P23-27:按照题目要求,创建了三个command*.c程序并编译生成了command *可执行文件用于测试

//command1.c
#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("command1 print\n");
    return 0;
}

P29:execv("/usr/bin/find",argv);,execv不像execl要一个一个传参数,而是直接提供指针数组就行了。因为find命令可以带很多参数就用这个了

P33:child == -1fork失败

注意:因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。所以创建子进程来提供exec执行命令程序的空间。(如下图可以看到,execl调用成功后不会打印success)
image20201203170427313.png

image20201203170401160.png

//输入参数带引号的情况,会将引号看作字符串的一部分
//下面是加了去引号的版本
int ParsePalam(char *buf, char** argv)
{
    int argv_idx, argc, flag = 0;
    argv_idx = argc = 0;
    while(argv_idx < MAX_ARG_NR)    //初始化
        argv[argv_idx++] = NULL;
    while(1){
        while(*buf == ' ')          //跳过空格
            buf++;
        if(*buf == '\n')            //碰到回车循环结束
            break;
        
        if(*buf == '"'){            //处理字符串的双引号
            flag = 1;
            argv[argc] = ++buf;
        }
        else
            argv[argc] = buf;       //记录参数首地址
        
        while(*buf != ' ' && *buf)  //确定参数结束地址
            buf++;
        if(!flag) 
            *buf++ = '\0';    		//添加字符串结束符
        else{
            *(buf++-1) = '\0';
            flag = 0;
        }
        if(argc > MAX_ARG_NR){      //超过最大参数数量error
            printf("argc is too large!\n");
            return -1;
        }
        argc++;
    }
    return argc;    //返回参数数量
}

解析参数的方法是用《操作系统真相还原》里的方法。

主要思路是argv[i]记录第i个参数的首地址,并把参数后面的空格换成结束符

举例:终端输入find . -name "main.c"\n,经过ParsePalam函数处理就变成find\0.\0-name\0"main,c"\0\n

argv[0]="find", argv[1]=".", argv[2]="-name", argv[3] = "main.c"

//判断是否是内置命令
int JudgeBuildin(char **argv)
{
    if(!strcmp(argv[0], "cd")){
        if(chdir(argv[1]))      //return -1 means error
            printf("dir isn't exist\n");
        return 1;
    }
    else if(!strcmp(argv[0], "pwd")){
        char buf[MAX_BUF];
        getcwd(buf, sizeof(buf));
        printf("%s\n", buf);
        return 1;
    }
    else if(!strcmp(argv[0], "exit") || !strcmp(argv[0], "q") ){
        exit(0);
    }
    return 0;
}

这部分没啥难度,也不是实验要求。

实例运行:

image20201210164100857.png

进程间通信 IPC(interprocess communication),指的是在多个并发进程之间进行的信息交换。

  • 低级方法:锁机制和信号量机制
  • 高级方法:管道通信、共享存储器、消息队列、客户-服务器通信(套接字和远程过程调用)

2) 阻塞性管道通信

问题:

  1. 父进程创建一个无名管道和三个子进程,三个子进程利用管道与之通信,父进程只有在全部子进程发送完消息后再接收数据。要求使用Posix信号量机制实现管道的互斥访问
  2. 用有名管道测试管道的大小

同步互斥关系

  1. 所有子进程对管道缓冲区的写数据存在互斥关系,使用write_psem=1进行约束
  2. 父进程要等待所有子进程写完数据后才能读,存在同步关系,使用read_psem[i]=0进行约束,当所有read_psem[i]=1时,父进程开始写数据
//问题一
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#define MAX_BUF 1024*64
#define CHILD_PROCESS_NUM 3
sem_t *write_psem;
sem_t *read_psem[CHILD_PROCESS_NUM];
char buf[MAX_BUF];
char *SEM_NAME[4] = {"sem0", "sem1", "sem2", "sem3"};   //给信号量命名
int main(int argc, char *argv[])
{
    int fd[2], pid[CHILD_PROCESS_NUM], i, count, ret_len, number;
    for(i = 0; i < CHILD_PROCESS_NUM; ++i)
        read_psem[i] = sem_open(SEM_NAME[i], O_CREAT, 0666, 0);
    write_psem = sem_open(SEM_NAME[3], O_CREAT, 0666, 1);
    if(pipe(fd) == -1){
        printf("pipe error\n");
        return -1;
    }
    for(i = 0; i < CHILD_PROCESS_NUM; ++i){
        if( (pid[i] = fork()) == -1){
            printf("error fork\n");
            return -1;
        }
        if(pid[i] == 0){
            sem_wait(write_psem);
            close(fd[0]);
            scanf("%d", &number);
            ret_len = write(fd[1], "A", number);      //写入number个‘A’,默认阻塞型写,如果管道满则阻塞
            printf("child %dth write length is: %d\n", i, ret_len);
            sem_post(write_psem);
            sem_post(read_psem[i]);
            return 0;   //子进程退出,父进程继续fork
        }
    }
    //等待所有子进程结束
    for(i = 0; i < CHILD_PROCESS_NUM; ++i)
        sem_wait(read_psem[i]);
    close(fd[1]);
    ret_len = read(fd[0], buf, MAX_BUF);
    close(fd[0]);
    printf("last: read %dB\n", ret_len);

    //信号量的彻底删除
    sem_close(write_psem);
    sem_unlink(SEM_NAME[3]);
    for(i = 0; i < CHILD_PROCESS_NUM; ++i){
        sem_unlink(SEM_NAME[i]);    //read_psem已经为0,不需要sem_close()减1
    }
    return 0;
}
//问题二
//mypipe3.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#define FILE_NAME "./myfifo"
#define MAX_BUF 1024*8
int main()
{
    int fd, ret_len, count, flags;
    if(access(FILE_NAME,F_OK) != 0){            //如果文件存在
        if(mkfifo(FILE_NAME, 0777) != 0){       //不存在就创建
            printf("error create file");
            return -1;
        }
    }
    if( (fd = open(FILE_NAME, O_RDWR)) < 0){    //打开有名管道
        printf("error open named pipe file");
        return -1;
    }
    flags = fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);  //设置非阻塞模式
    count = 0;
    while( (ret_len = write(fd, "A", MAX_BUF)) != -1){
        count++;
        printf("the %dth write %dB\n", count, ret_len);
    }
    printf("max of pipe length is %dKB\n", count*MAX_BUF/1024);
    sleep(10);
    return 0;
}

测试管道大小,就是不断往管道写数据直到写不进去,记录总共写了多少数据即可

这里将管道设置为非阻塞模式,所以当管道满的时候,返回值为-1。

//mypipe2.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#define FILE_NAME "./myfifo"
#define MAX_BUF 1024*8
char buf[MAX_BUF];
int count, ret_len, flags;
int main(int argc, char *argv[])
{
    int fd;
    if(access(FILE_NAME,F_OK) != 0){            //如果文件存在
        if(mkfifo(FILE_NAME, 0777) != 0){       //不存在就创建
            printf("error create file");
            return -1;
        }
    }
    if( (fd = open(FILE_NAME, O_RDWR)) < 0){    //打开有名管道
        printf("error open named pipe file");
        return -1;
    }
    flags = fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);  //设置非阻塞模式
    count = 0;
    while( (ret_len = read(fd, "A", MAX_BUF)) != -1){	//读管道数据
        count++;
        printf("the %dth read %dB\n", count, ret_len);
    }
    return 0;
}

实例运行:

image20201210173203342.png

参考:

多次读管道的问题

等待所有子进程结束

POSIC库文件的编译问题

https://leslievan.github.io/2019/04/os-lab-3-2/#%E5%AE%9E%E9%AA%8C%E5%86%85%E5%AE%B9

3)消息队列+信号量

问题:基本要求+多进程同步+互斥通信

//自定义头文件
#ifndef EXP3_3_COMMON_H
#define EXP3_3_COMMON_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sys/msg.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <time.h>
#define QUEUE_ID    10086
#define MAX_SIZE    1024
#define MSG_STOP    "exit"
#define snd_to_rcv1 1
#define snd_to_rcv2 2
#define rcv_to_snd1 3
#define rcv_to_snd2 4
#define CHECK(x) \
    do { \
        if (!(x)) { \
            fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
            perror(#x); \
            exit(-1); \
        } \
    } while (0) \


/* global variable */
sem_t *w_mutex, *empty, *full, *over, *rcv_dp, *snd_dp, *finish;
char *SEM_NAME[7] = {"w_mutex", "empty","full", "over", "rcv_dp", "snd_dp", "finish"};

void create_sem()
{
    w_mutex = sem_open(SEM_NAME[0], O_CREAT, 0666, 1);
    empty = sem_open(SEM_NAME[1], O_CREAT, 0666, 10);
    full = sem_open(SEM_NAME[2], O_CREAT, 0666, 0);
    over = sem_open(SEM_NAME[3], O_CREAT, 0666, 0);
    rcv_dp = sem_open(SEM_NAME[4], O_CREAT, 0666, 0);
    snd_dp = sem_open(SEM_NAME[5], O_CREAT, 0666, 1);
    finish = sem_open(SEM_NAME[6], O_CREAT, 0666, 0);
    return ;
}
void release_sem()
{
    int i;
    sem_close(w_mutex);
    for(i = 0; i < 10; ++i)
        sem_close(empty);
    sem_close(snd_dp);
    for(i = 0; i < 7; ++i)
        sem_unlink(SEM_NAME[i]);
    return ;
}

#define P(x) sem_wait(x)
#define V(x) sem_post(x)
struct msg_st {
    long int message_type;
    char buffer[MAX_SIZE];
};

//进程随机获得写数据的机会
int get_chance(int range)
{
    srand((unsigned)time(NULL));
    return rand()%range;
}
#endif //EXP3_3_COMMON_H
//sender1.c
#include "common.h"

int main(){
    int mq;
    struct msg_st buf;
    ssize_t bytes_read;
    //创建或者打开有名信号量
    create_sem();
    //创建消息队列
    mq = msgget((key_t) QUEUE_ID, 0666 | IPC_CREAT);
    CHECK((key_t) -1 != mq);

    do {
        printf("sender1> ");
        fflush(stdout);
        fgets(buf.buffer, MAX_SIZE, stdin);
        buf.message_type = snd_to_rcv1;
        /* send the message */
        P(empty);
        P(w_mutex);
        CHECK(0 <= msgsnd(mq, (void*)&buf, MAX_SIZE, 0));
        V(full);
        V(w_mutex);
     } while (strncmp(buf.buffer, MSG_STOP, strlen(MSG_STOP)));

    /* wait for response */
    P(over);
    bytes_read = msgrcv(mq, (void *) &buf, MAX_SIZE, rcv_to_snd1, 0);
    CHECK(bytes_read >= 0);
    printf("%s", buf.buffer);
    V(finish);
    return 0;
}
//sender2.c
#include "common.h"

int main(){
    int mq;
    struct msg_st buf;
    ssize_t bytes_read;
    //创建或者打开有名信号量
    create_sem();
    //创建消息队列
    mq = msgget((key_t) QUEUE_ID, 0666 | IPC_CREAT);
    CHECK((key_t) -1 != mq);

    do {
        printf("sender2> ");
        fflush(stdout);
        fgets(buf.buffer, MAX_SIZE, stdin);
        buf.message_type = snd_to_rcv2;
        /* send the message */
        P(empty);   //
        P(w_mutex);
        CHECK(0 <= msgsnd(mq, (void*)&buf, MAX_SIZE, 0));
        V(full);
        V(w_mutex);
     } while (strncmp(buf.buffer, MSG_STOP, strlen(MSG_STOP)));

    /* wait for response */
    P(over);
    bytes_read = msgrcv(mq, (void *) &buf, MAX_SIZE, 0, 0);
    CHECK(bytes_read >= 0);
    printf("%s", buf.buffer);
    V(finish);
    return 0;
}
//receiver.c
#include "common.h"
int main()
{
    create_sem();
    struct msg_st buf, over1, over2;
    int mq, must_stop = 2;
    struct msqid_ds t;
    over1.message_type = 3;
    strcpy(over1.buffer, "over1\n");
    over2.message_type = 4;
    strcpy(over2.buffer, "over2\n");

    /* open the mail queue */
    mq = msgget((key_t) QUEUE_ID, 0666 | IPC_CREAT);
    CHECK((key_t) -1 != mq);

    do {
        ssize_t bytes_read, bytes_write;
        /* receive the message */
        P(full);
        bytes_read = msgrcv(mq, (void *) &buf, MAX_SIZE, 0, 0);
        V(empty);
        CHECK(bytes_read >= 0);
        if (!strncmp(buf.buffer, MSG_STOP, strlen(MSG_STOP))) {
            if (buf.message_type == 1) {
                printf("send over1 to sender1\n");
                bytes_write = msgsnd(mq, (void *) &over1, MAX_SIZE, 0);
                CHECK(bytes_write >= 0);
                V(over);
                must_stop--;
            } else if (buf.message_type == 2) {
                printf("send over2 to sender2\n");
                bytes_write = msgsnd(mq, (void *) &over2, MAX_SIZE, 0);
                CHECK(bytes_write >= 0);
                V(over);
                must_stop--;
            }
        } else {
            printf("Received%ld: %s", buf.message_type, buf.buffer);
        }
    } while (must_stop);

    P(finish);
    P(finish);
    CHECK(!msgctl(mq, IPC_RMID, &t));
    release_sem();
    return 0;
}

实例演示:

image.png

image.png

image.png

4)共享内存

同步和互斥关系

  1. sender和receiver需要互斥访问共享内存,用sh_mutex
  2. receiver需要等待sender发送数据后,再读共享内存。存在同步关系,用wait_sender
  3. sender发送消息后需要receiver发送应答消息后才能读共享空间。存在同步关系,用wait_receiver
//自定义头文件
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <string.h>
#define MAX_SIZE 1024
#define SH_ADDRESS1 10000
#define SH_ADDRESS2 10001
struct shared_user_st
{
    char text[MAX_SIZE];
};
#define CHECK(x) \
    do { \
        if (!(x)) { \
            fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
            perror(#x); \
            exit(-1); \
        } \
    } while (0) \

/*sem*/
#define P(x) sem_wait(x);
#define V(x) sem_post(x);
sem_t  *wait_sender1, *wait_receiver1, *wait_sender2, *wait_receiver2;
char *SEM_NAME[4] = {"s1", "s2", "s3", "s4"};
void create_sem()
{
    wait_sender1 = sem_open(SEM_NAME[0], O_CREAT, 0666, 0);
    wait_sender2 = sem_open(SEM_NAME[2], O_CREAT, 0666, 0);
    wait_receiver1 = sem_open(SEM_NAME[1], O_CREAT, 0666, 0);
    wait_receiver2 = sem_open(SEM_NAME[3], O_CREAT, 0666, 0);
}
void release_sem()
{
    int i;
    for(i = 0; i < 4; ++i)
        sem_unlink(SEM_NAME[i]);
}
#endif
//receiver.c
#include "common.h"

int main()
{
    void *shm1 = NULL, *shm2 = NULL;
    struct shared_user_st *shared1, *shared2 ; //point to shm
    int shmid1, shmid2;
    char buffer[MAX_SIZE];
    create_sem();
    shmid1 = shmget((key_t)SH_ADDRESS1, sizeof(struct shared_user_st), 0666|IPC_CREAT);
    shmid2 = shmget((key_t)SH_ADDRESS2, sizeof(struct shared_user_st), 0666|IPC_CREAT);
    CHECK(shmid1 != -1);
    CHECK(shmid2 != -1);
    int pid = fork();
    if(pid == 0){
        while(1){
        P(wait_sender1);  //父进程等待发送方的消息
        shm1 = shmat(shmid1, NULL, 0);
        CHECK(shm1 != (void *)-1);
        shared1 = (struct shared_user_st *)shm1;
        strncpy(buffer, shared1->text,MAX_SIZE);
        printf("\nreceive:%s\n", buffer);
        strcat(buffer, " over");
        memcpy(shared1->text, buffer, sizeof(buffer));
        shmdt(shm1);        //分离出用户空间
        V(wait_receiver2);  //让2号进程知道已经有应答了
        }
    }
    else if (pid > 0){
        while(1){
        shm2 = shmat(shmid2, NULL, 0);
        CHECK(shm2 != (void *)-1);
        shared2 = (struct shared_user_st *)shm2;
        printf("please send:\n");
        scanf("%s",buffer);
        memcpy(shared2->text, buffer, sizeof(buffer));
        V(wait_sender2);

        P(wait_receiver1);  //2号进程已经发出了应答
        strcpy(buffer, shared2->text);
        printf("\nreturn:%s\n", buffer);
        shmdt(shm2);
        }
    }
    else{
        printf("fork error\n");
        return -1;
    }
    release_sem();
    return 0;
}
//sender.c
#include "common.h"

int main()
{
    void *shm1 = NULL, *shm2 = NULL;
    struct shared_user_st *shared1, *shared2 ; //point to shm
    int shmid1, shmid2;
    char buffer[MAX_SIZE];
    create_sem();
    shmid1 = shmget((key_t)SH_ADDRESS1, sizeof(struct shared_user_st), 0666|IPC_CREAT);
    shmid2 = shmget((key_t)SH_ADDRESS2, sizeof(struct shared_user_st), 0666|IPC_CREAT);
    CHECK(shmid1 != -1);
    CHECK(shmid2 != -1);
    int pid = fork();
    if(pid == 0){
        while(1){
        P(wait_sender2);  //父进程等待发送方的消息
        shm2 = shmat(shmid2, NULL, 0);
        CHECK(shm2!= (void *)-1);
        shared2 = (struct shared_user_st *)shm2;
        strncpy(buffer, shared2->text,MAX_SIZE);
        printf("\nreceive:%s\n", buffer);
        //scanf("%s", buffer);
        strcat(buffer, " over");
        memcpy(shared2->text, buffer, sizeof(buffer));
        shmdt(shm2);        //分离出用户空间
        V(wait_receiver1);  //让2号进程知道已经有应答了
        }
    }
    else if (pid > 0){
        while(1){
        shm1 = shmat(shmid1, 0, 0);
        CHECK(shm1 != (void *)-1);
        shared1 = (struct shared_user_st *)shm1;
        printf("please send:\n");
        scanf("%s",buffer);
        memcpy(shared1->text, buffer, sizeof(buffer));
        V(wait_sender1);

        P(wait_receiver2);  //2号进程已经发出了应答
        strcpy(buffer, shared1->text);
        printf("\nreturn:%s\n", buffer);
        shmdt(shm1);
        }
    }
    else{
        printf("fork error\n");
        return -1;
    }
    release_sem();
    return 0;
}

实例演示:
image.png

image.png


标题:杭电操作系统实验三:linux进程管理
作者:abandon
地址:HTTPS://www.songsci.com/articles/2021/04/03/1.html

Life Is Like A Boat

取消