系统IO文件共享与重定向(习题分析)

文件共享与重定向

考完才知道第十章还发了代码没跑,考试还考了里面的题,而考场才第一次见的我一波自信的分析最后做出来还是错了。吸取教训:1.作业不要拖到最后做,最好及时到发出来的前两天就做好。2.机器跑代码看结果才是王道,理论分析只是你个人的分析,你没有你想的那么懂系统(害,一声长叹

前提知识

老师发的3个题主要是和共享文件和重定向相关,在开始之前,我们先了解一下内核表示打开的文件用到的相关数据结构:
1.描述符表。每个进程一个,表项由该进程打开的文件描述符来索引,每个表项指向一个文件表中的一个表项。
2.文件表。所有进程共享,所有打开文件的集合。表项中包括当前的文件位置(可以理解为光标位置),引用计数(refcnt),以及一个指向v-node表的指针。每open一次初始化一个表项(我个人的理解,如有错误欢迎指出)
3.v-node表。所有进程共享,每个表项里是文件的元数据(即data of data)
在这里插入图片描述

代码以及对机器运行结果的分析

接下来我们可以来看看代码了:

//ffiles1.c
int main(int argc, char *argv[])
{
    int fd1, fd2, fd3;
    char c1, c2, c3;
    char *fname = argv[1];
    fd1 = Open(fname, O_RDONLY, 0);
    fd2 = Open(fname, O_RDONLY, 0);
    fd3 = Open(fname, O_RDONLY, 0);
    dup2(fd2, fd3);//该函数将用fd2表项内容覆盖fd3表项内容
    
    Read(fd1, &c1, 1);
    Read(fd2, &c2, 1);
    Read(fd3, &c3, 1);
    printf("c1 = %c, c2 = %c, c3 = %c\n", c1, c2, c3);
    Close(fd1);
    Close(fd2);
    Close(fd3);
    return 0;
}

在这里插入图片描述
这里的abcde.txt文件内容为abcde。
分析:
fd1和fd2是各自open文件得到的描述符,所以他们各自指向一个文件表表项,拥有各自的光标,读到的字符都是第一个字符a,而fd3描述表项内容被fd2覆盖,所以fd3和fd2指向同一个文件表表项,当轮到fd3读文件时,从fd2读过后的位置开始,得到b。

第一题比较基础,我们接下来进阶一下(虽然其实都不是啥难题,害)

//ffiles2.c
int main(int argc, char *argv[])
{
    int fd1;
    int s = getpid() & 0x1;
    char c1, c2;
    char *fname = argv[1];
    fd1 = Open(fname, O_RDONLY, 0);
    Read(fd1, &c1, 1);
    if (fork()) {
 /* Parent */
 sleep(s);
 Read(fd1, &c2, 1);
 printf("Parent: c1 = %c, c2 = %c\n", c1, c2);
    }else {
 /* Child */
 sleep(1-s);
 Read(fd1, &c2, 1);
 printf("Child: c1 = %c, c2 = %c\n", c1, c2);
    }
    return 0;
}

在这里插入图片描述
分析:
父进程打开文件得到描述符fd1,并读得c1为第一个字符为a,接下来休眠等待fork出的子进程结束(s不会大于1,父进程休眠时间比子进程长,效果相当于等子进程结束),子进程继承了父进程打开的文件,所以子进程描述符表中的fd1项和父进程指向同一个文件表,共享同一个光标位置,读到的c2为a之后的b。子进程结束后再回到父进程读该进程里的c2,依然是同一个光标,得到后面的c。

//ffiles3.c
int main(int argc, char *argv[])
{
    int fd1, fd2, fd3;
    char *fname = argv[1];
    fd1 = Open(fname, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR);
    Write(fd1, "pqrs", 4);
 
    fd3 = Open(fname, O_APPEND|O_WRONLY, 0);
    Write(fd3, "jklmn", 5);
    fd2 = dup(fd1);  /* Allocates new descriptor */
    Write(fd2, "wxyz", 4);
    Write(fd3, "ef", 2);
    Close(fd1);
    Close(fd2);
    Close(fd3);
    return 0;
}

运行后打开abcde.txt我们看到:
在这里插入图片描述
这就是那道我自以为我懂了其实我错了的考题。
分析:
这道和上面那道的文件表指向情况没区别,不过这里用了写函数稍微复杂一点。我错在写入方式的理解上了,我以为是从光标处插入写,然而事实证明我想得太美好了,机器并不知道光标后面有没有你要的数据,直接从文件位置写,原位置有字符直接用新值覆盖。
所以fd1打开abcde.txt后清空原有内容,写入pqrs,接下来再次打开该文件得到fd3,因为打开方式带追加标志,所以接下来的jklmn在s后写入,因为fd2和fd1是指向同一个文件表项的,所以wxyz是在上一次对fd1写入后的光标位置开始写的,原来s后面有jklmn5个字符,被wxyz覆盖后还幸存了一个n,接着继续对fd3的写入,从fd3指向文件表项里的文件位置(n的后面)写入ef.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值