UNIX环境高级编程———第三章习题

1.当读/写磁盘文件时,本章中描述的函数确实是不带缓存机制的吗?

答:首先我们来说明缓存的:不带缓存的I/O和带缓存的I/O(标准I/O)

(1)不带缓存的I/O:数据——内核缓存区——磁盘(硬盘);只有系统调用;文件描述符

当进行读写操作时,数据直接进行系统调用(read,write),进入内核缓存区,然后等待内核缓存存满之后将数据写入到磁盘。

假如内核缓存区在缓存满10个字节就将数据写入到磁盘,假设我每次写入1个字节,那么我需要写入10次才能保证所有数据肯定被存入硬盘(此处假设开始时内核缓存区为0字节),也就是说我需要进行10次系统调用。

(2)带缓存的I/O    :数据——用户缓存区——内核缓存区——磁盘(硬盘);系统调用[1]和函数库调用[2];数据流

当进行读写操作时,数据首先进行函数调用(fread,fwrite),进入到用户缓存区,然后等待用户缓存区存满了之后进行系统调用(write,read),进入到内核缓存区,等待内核缓存区存满之后将数据写入磁盘。

假设内核缓存区在缓存满10个字节就将数据写入到磁盘,用户缓存区写满5个就将数据写入到内核缓存区,那么我每次写1个字节,那么如果要将数据写入到磁盘,我至少需要写入10次,(此处假设开始时用户缓存区和内核缓存区为0个字节),2次10次函数调用,2次系统调用。

总结:就上面的例子进行比较,因为使用系统调用会影响系统的性能。与函数调用相比,系统调用时,Linux必须从运行用户代码切换到执行内核代码,然后再返回用户代码,所以系统调用的开销要比普通函数调用大一些。所以可想而知,带缓存的I/O要比不带缓存的I/O效率高很多。

然后我们来解答次题:

本章中的不带缓存的函数并不是不带缓存,只是不带用户缓存。

注释:

[1]系统调用:操作系统的主要功能是为管理硬件资源和为应用程序开发人员提供良好的环境来使应用程序具有更好的兼容性,为了达到这个目的,内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序。

[2]关于内核读写函数:http://blog.csdn.net/tommy_wxie/article/details/8194276

原文地址:http://blog.csdn.net/melanie327/article/details/8275909

2.编写一个与3.12中dup2功能相同的函数,要求不调用fcntl函数,并且有正确的报错(这个程序存在问题,求大家指出错误)

#include "apue.h"
#include "unistd.h"
int main(void)
{
        int fd,fd2;
        if ((fd=open("/home/mocun/unix/chapter1/try",0)) < 0) /*获取try这个文件的描述符*/
                err_quit("open error");
        printf("fd is %d \n",fd);
        fd2 = dup3(fd,19);/*调用dup3将复制这个文件描述符为19*/
        printf("succeed find the %d",fd2);
        close(fd2);
}

int dup3(int fd,int new_fd)
{
        int i,a,index[100],tmpfd;
        if (fd == new_fd) /*判断19与文件本身是否相等*/
                return fd;
        for (i = 0;new_fd != fd ;++ i)  /*如果不相同,则使用dup不断的获取文件描述符,知道与19相等*/
        {                       
                index[i] = fd;
                fd = dup(fd);
        }       
        printf("find the fd %d:\n",fd);
        if (write(fd,"i try",10) < 0)  /*为了检验是否正确,我尝试打开文件写入数据,但是失败,所以现在这个程序应该还是有问题的*/
                err_sys("write error!");
        for (a = 0;a <= i;++ a) 
                close(index[a]);
        return fd;
}
3.假设一个进程执行下面的3个函数调用

fd1 = open(path,oflags)

fd2 = dup(fd1)

fd3 = open(path,oflags)

(1)

        UNIX环境高级编程———第三章习题_第1张图片

fcntl作用于fd1来说, F_SETFD命令会影响哪一个文件描述符?F_SETFL呢?

(2)F_SETFD:只是修改文件描述符标志(文件描述符标志的解释:http://blog.csdn.net/lott_mocun/article/details/48791173http://)

(3)F-GETFD:只是修改文件状态标志(只读,只写,......等)

4.许多程序都包括下面的程序:

dup2(fd,0)

dup2(fd,1)

dup2(fd,2)

if (fd > 2)

     close(fd);

为了说明if语句的必要性,假设if时1,画出每次调用dup2时3个描述符项及相应的文件表项的变化情况,然后再画出fd为3的情况。

5.在Bourne,Bourne_again shell 和 Korn shell 中,digital1>digital2表示要将描述符digital重定向之描述符digital2的同一文件。请说明下面两条命令的区别。

(1)./a.out  >  outfile  2>&1

因为shell命令是从左到右执行的,所以从左到右一次分析命令之间的关系,首先将标准输出(输出到shell屏幕)重定向为输出到outfile,即将./a.out的结果输入到outfile,然后将错误输出文件描述符2重定向为标准输出。结果是描述符1指向outfile的文件表项,描述符 2指向终端的文件表项

./a.out  2>&1  > outfile

首先将错误输出文件描述符2重定向为标准输出,然后将标准输出(输出到shell屏幕)重定向为输出到outfile,即将./a.out的结果输入到outfile。结果是描述符1指向outfile的文件表项,描述符 2指向终端的文件表项。

6.如果使用追加标志打开一个文件以便读写,能否仍用lseek在任意位置开始读?能否用lseek更新文件中任一部分的数据?请编写一段程序验证

答:这种情况之下,仍然可以用lseek和read函数读文件中任意一处的内容。但是 write函数在写数据之前会自动将文件位移量设置为文件尾,所以写文件时只能从文件尾开始,不能在任意位置。

编写的程序:

#include "apue.h"
#include 

int main(void)
{

        int fd;
        char buf1[20]; /*定义一个字符串用来读取文件中的字符*/
        char buf2[10]="onetwothre";/*用来写入的字符串*/
        if ((fd = open("/home/mocun/unix/chapter1/try",2|O_APPEND)) < 0)/*使用追加方式打开文件*/
                printf("open error! \n");
        if (lseek(fd,5,SEEK_SET) < 0) /*将文件的偏移量设置为5*/
                printf("lseek error! \n");
        if (read(fd,buf1,5) < 0)     /*从偏移量为5处读出五个字符*/
                printf("read error! \n");
        else
                printf("read:%s",buf1);/*将读出的字读输出*/
        if (write(fd,buf2,10) < 0)    /*将字符串buf2写入文件*/
                printf("write error! \n");
}

文件的初始状态:

运行程序后:

shell输出结果:


你可能感兴趣的:(APUE知识点整理)