6.s081 实验1 记录


6s081这个课搁置一段时间了,最近才把实验2做完,特意开个博客记录,当着一个监督吧。
实验一没什么前置知识,配置好环境,会c语言直接就可以做。
Lab util: Unix utilities

test_pipe.c

#include "kernel/stat.h"
#include "user/user.h"
int main(int avgc, char* argv[]) {
    
    char buf[1];
    char abyte[] = "abc";
    int p[2];
    pipe(p);
    int pid = fork();

    if (pid == 0) {
        // child
        printf("child's pid is %d \n", getpid());
        printf("waiting parent to write\n");

        // read block until data have been written
        // or all write end have been closed
        close(p[1]); // 必须同时close掉parent和child的p[1],read才不会阻塞
        read(p[0], buf,1);
        printf("char = %c\n", buf[0]);
        exit(0);
    } else {
        //parent
        close(p[1]); // 注释这行,则子进程的read会阻塞
        sleep(20);
        write(p[1], abyte, sizeof abyte);

        int status=0;
        wait(&status); //wait child exit, return child'pid
        printf("parent's pid = %d \n", getpid());
        //printf("child exit with status %d\n", status);
    }
    exit(0);
}
  • pipe§ 会产生返回两个fd, 放在p中,p[0]的读取端的fd,p[1]是写入端的fd;
  • read(p[0], buf, n)表示从p[0]读取n个字节到buf中;从p[0]读取时,若未有数据write到p[1],read会阻塞
  • 但若pipe的所有write end 都被close,read会返回0然后结束,表示读取了0个字节。
  • 上面因为使用了fork(), 所有必须在parent和child中均关闭p[1], read才不会阻塞。

primes.c

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(int argc, char *argv[]){
    int p1[2], p2[2];
    int *tmp1, *tmp2;
    pipe(p1);
    pipe(p2);
    tmp1 = p1;   // for exchange p1,p2
    tmp2 = p2;
    int buf[1];
    for(int i = 2; i <= 35; i++)
        write(tmp1[1], &i,1);

    
    // close(tmp1[1]);   //*0, 若不在此处close(tmp1[1]), 父子进程需要各自关闭tmp1[1]
    
    while (fork()==0) {
        close(tmp1[1]);  // *2
        if (read(tmp1[0], buf, 1) == 1) {  // *1
            int p = buf[0];
            printf("primes: %d\n", p);
            int n;
            // if (p == 2)      // *3
            //     close(tmp1[1]);
            while (read(tmp1[0], buf, 1) == 1) { //*4
                
                n =  buf[0];
                if (n%p != 0) {
                    write(tmp2[1], buf, 1);
                }
            }
            close(tmp1[0]);
            // close(tmp2[0]);  //不能关闭此处的tmp2[0],它决定了是子进程的tmp1[0]的
            // 状态, 关闭了, *1处会阻塞
            
            // close(tmp2[1]); // 此处决定着子进程tmp1[1]的状态,可以提前关闭。作用
            //与*2处类似, 但若在此处关闭,则需加上3*处代码,因为第一次fork()进入到 *4 // 时,tmp1[1]未关闭,*4会阻塞。 
            //*0是最省事的方法,fork()前关闭tmp1[1];

            pipe(tmp1);
            int * tmp = tmp1;
            tmp1 = tmp2;
            tmp2 = tmp;
            
        } else {
            close(tmp1[0]);
            // close(tmp1[1]);
            close(tmp2[1]);
            close(tmp2[0]);
            exit(0);
        }

    }
    close(tmp1[1]);
    close(tmp1[0]);
    close(tmp2[1]);
    close(tmp2[0]);
    wait(0);
    
    // printf("parent id = %d \n", getpid());
    exit(0);
}

注意:

  • while( fork() == 0) 这个语句, 会产生一个子进程,当前进程则会跳过while,执行到wait(0);等待子进程的完成。 例如,假设main进程pid = 4, 第一次fork()产生一个pid=5的子进程, 而pid=4的进程则是在wait; pid=5的进程执行while内的语句,如果if (read(tmp1[0], buf, 1) == 1)满足,则执行往if内语句后,再次执行到 while(fork()==0),此处产生一个pid=6的子进程,而pid=5的进程则会执行到wait(0);处等待。在pid=6进程中,若if语句成立,则继续fork(), 若if语句不成立,这会执行else语句中的exit(0), 则此时进程结束。
    我们假设在pid=6进程中执行了else,进程结束。 这pid=5的进程wait得以执行完成,执行wait下面的exit(0), pid=5的进程结束。这时,最开始的main进程(pid=4)中,wait得以执行完成,继续执行其下面的exit(0); 整个程序结束。
  • fork() 产生的子进程会继承父进程的变量及其状态。因此,若在fork()前关闭了pipe的写入或读取fd,在子进程中对应fd也是关闭状态。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值