zoukankan      html  css  js  c++  java
  • 用户态与内核态 & 文件流与文件描述符 简介

    用户态和内核态

    程序代码的依赖和调用关系如下图所示:
    mark

    • Lib:标准ASCI C函数,几乎所有的平台都支持该库函数,因此依赖该库的程序可移植性好;
    • System Function:系统调用函数,与系统内核进行交互,不同平台具备不同的函数接口,因此可移植性较差

    区分用户态和内核态主要是由于系统资源的有限性,不能无限制的随意分配给用户使用,必须由系统进行统一管理

    • User mode:不能直接对系统资源进行访问,如果要操作系统资源,必须转化为内核态
    • Kernel mode:管理系统资源,可直接对系统资源进行控制和访问

    内核为用户提供了统一的API供其使用,不同的系统的API接口不同,为了便于代码的移植,出台了POSIX标准,类Unix系统(Unix、Linux、BSD、SunOS等)均支持该标准。

    文件流与文件描述符

    • 问题
      由上图我们可看到,每执行一次系统调用,都要涉及到CPU状态的切换,即从用户态切换到内核态,即从用户空间切换到内核空间,实现上下文切换的过程,会消耗相当一部分的CPU资源,因此频繁的磁盘访问对程序的执行效率将造成很大影响。

    • 解决方案
      为了解决以上的难题,采用了缓冲区的概念,当对磁盘文件进行操作时,可一次性从磁盘文件中读出大量的数据暂放到缓冲区中,以后对这部分数据的访问就不需要再进行系统调用了;当对文件行操作后,可将处理后的数据暂存到输出缓冲区,待文件缓冲区满后,一次性写入到磁盘。

    mark

    以上,数据的输入输出就像是水在流动一样,因此我们采用了的概念。

    • 文件流
      简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向;
      文件流用结构体表示:struct FILE.
      FILE的结构体又是怎么样的呢?我们可以进行查找一下:

        [niesh@niesh ~]$ vim /usr/include/stdio.h
      

    我们看到了 stdio.h的文件中有一行:

    __BEGIN_NAMESPACE_STD
     /* The opaque type of streams.  This is the definition used elsewhere.  */
     typedef struct _IO_FILE FILE;
     __END_NAMESPACE_STD
    

    显然,FILE_IO_FILE的类型替换,那么我们找一下 _IO_FILE在哪里呢?

    [niesh@niesh ~]$ grep -rn "<_IO_FILE>" /usr/include/
    /usr/include/c++/4.8.2/streambuf:178:       *  This is based on _IO_FILE, just reordered to be more consistent,
    /usr/include/libio.h:145:struct _IO_jump_t;  struct _IO_FILE;
    /usr/include/libio.h:163:  struct _IO_FILE *_sbuf;
    /usr/include/libio.h:246:struct _IO_FILE {              //此处正解
    /usr/include/libio.h:267:  struct _IO_FILE *_chain;
    /usr/include/libio.h:291:  struct _IO_FILE _file;
    /usr/include/libio.h:299:  struct _IO_FILE *_freeres_list;
    /usr/include/libio.h:316:typedef struct _IO_FILE _IO_FILE;
    /usr/include/libio.h:325:#define _IO_stdin ((_IO_FILE*)(&_IO_2_1_stdin_))
    /usr/include/libio.h:326:#define _IO_stdout ((_IO_FILE*)(&_IO_2_1_stdout_))
    /usr/include/libio.h:327:#define _IO_stderr ((_IO_FILE*)(&_IO_2_1_stderr_))
    /usr/include/libio.h:329:extern _IO_FILE *_IO_stdin attribute_hidden;
    /usr/include/libio.h:330:extern _IO_FILE *_IO_stdout attribute_hidden;
    /usr/include/libio.h:331:extern _IO_FILE *_IO_stderr attribute_hidden;
    /usr/include/libio.h:391:extern int __underflow (_IO_FILE *);
    /usr/include/libio.h:392:extern int __uflow (_IO_FILE *);
    /usr/include/libio.h:393:extern int __overflow (_IO_FILE *, int);
    /usr/include/libio.h:395:extern _IO_wint_t __wunderflow (_IO_FILE *);
    /usr/include/libio.h:396:extern _IO_wint_t __wuflow (_IO_FILE *);
    /usr/include/libio.h:397:extern _IO_wint_t __woverflow (_IO_FILE *, _IO_wint_t);
    /usr/include/libio.h:435:extern int _IO_getc (_IO_FILE *__fp);
    /usr/include/libio.h:436:extern int _IO_putc (int __c, _IO_FILE *__fp);
    /usr/include/libio.h:437:extern int _IO_feof (_IO_FILE *__fp) __THROW;
    /usr/include/libio.h:438:extern int _IO_ferror (_IO_FILE *__fp) __THROW;
    /usr/include/libio.h:440:extern int _IO_peekc_locked (_IO_FILE *__fp);
    /usr/include/libio.h:446:extern void _IO_flockfile (_IO_FILE *) __THROW;
    /usr/include/libio.h:447:extern void _IO_funlockfile (_IO_FILE *) __THROW;
    /usr/include/libio.h:448:extern int _IO_ftrylockfile (_IO_FILE *) __THROW;
    /usr/include/libio.h:465:extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
    /usr/include/libio.h:467:extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
    /usr/include/libio.h:469:extern _IO_ssize_t _IO_padn (_IO_FILE *, int, _IO_ssize_t);
    /usr/include/libio.h:470:extern _IO_size_t _IO_sgetn (_IO_FILE *, void *, _IO_size_t);
    /usr/include/libio.h:472:extern _IO_off64_t _IO_seekoff (_IO_FILE *, _IO_off64_t, int, int);
    /usr/include/libio.h:473:extern _IO_off64_t _IO_seekpos (_IO_FILE *, _IO_off64_t, int);
    /usr/include/libio.h:475:extern void _IO_free_backup_area (_IO_FILE *) __THROW;
    /usr/include/libio.h:478:extern _IO_wint_t _IO_getwc (_IO_FILE *__fp);
    /usr/include/libio.h:479:extern _IO_wint_t _IO_putwc (wchar_t __wc, _IO_FILE *__fp);
    /usr/include/libio.h:480:extern int _IO_fwide (_IO_FILE *__fp, int __mode) __THROW;
    /usr/include/libio.h:514:extern int _IO_vfwscanf (_IO_FILE * __restrict, const wchar_t * __restrict,
    /usr/include/libio.h:516:extern int _IO_vfwprintf (_IO_FILE *__restrict, const wchar_t *__restrict,
    /usr/include/libio.h:518:extern _IO_ssize_t _IO_wpadn (_IO_FILE *, wint_t, _IO_ssize_t);
    /usr/include/libio.h:519:extern void _IO_free_wbackup_area (_IO_FILE *) __THROW;
    /usr/include/stdio.h:44:struct _IO_FILE;
    /usr/include/stdio.h:48:typedef struct _IO_FILE FILE;
    /usr/include/stdio.h:64:typedef struct _IO_FILE __FILE;
    /usr/include/stdio.h:168:extern struct _IO_FILE *stdin;         /* Standard input stream.  */
    /usr/include/stdio.h:169:extern struct _IO_FILE *stdout;                /* Standard output stream.  */
    /usr/include/stdio.h:170:extern struct _IO_FILE *stderr;                /* Standard error output stream.  */
    

    (⊙o⊙)…,还挺多啊,不过仔细观察,发现只有 libio.h的246行是对该结构体的定义,我们打开瞅瞅!

    [niesh@niesh ~]$ vim /usr/include/libio.h
    

    struct FILE 的结构体成员如下代码所示:

        struct _IO_FILE {
          int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
        #define _IO_file_flags _flags
        
          /* The following pointers correspond to the C++ streambuf protocol. */
          /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
          char* _IO_read_ptr;   /* Current read pointer */
          char* _IO_read_end;   /* End of get area. */
          char* _IO_read_base;  /* Start of putback+get area. */
          char* _IO_write_base; /* Start of put area. */
          char* _IO_write_ptr;  /* Current put pointer. */
          char* _IO_write_end;  /* End of put area. */
          char* _IO_buf_base;   /* Start of reserve area. */
          char* _IO_buf_end;    /* End of reserve area. */
          /* The following fields are used to support backing up and undo. */
          char *_IO_save_base; /* Pointer to start of non-current get area. */
          char *_IO_backup_base;  /* Pointer to first valid character of backup area */
          char *_IO_save_end; /* Pointer to end of non-current get area. */
        
          struct _IO_marker *_markers;
        
          struct _IO_FILE *_chain;
        
          int _fileno;
        #if 0
          int _blksize;
        #else
          int _flags2;
        #endif
          _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
        
        #define __HAVE_COLUMN /* temporary */
          /* 1+column number of pbase(); 0 is unknown. */
          unsigned short _cur_column;
          signed char _vtable_offset;
          char _shortbuf[1];
        
          /*  char* _save_gptr;  char* _save_egptr; */
        
          _IO_lock_t *_lock;
        #ifdef _IO_USE_OLD_IO_FILE
        };
    
    • 文件描述符
      每个进程,当打开一个文件后,内核会为其建立一个打开文件的数组 (数组的前三个为stdin,stdout,stderr),然后返回打开文件位于数组的索引值(下标),该所以只即为文件描述符,只要文件不关闭,用户便可以根据该描述符对文件进行访问和操作。

    • 不同点
      文件描述符:表示为int类型的对象:如stdin对应文件描述符0,stdout对应文件描述符1;
      :表示为指向结构FILE的指针FILE* ,因此流也称为文件指针
      若需要对特定设备进行控制操作,必须使用文件描述符方式,没有函数能对流进行这类操作
      如果需要按照特殊的方式进行I/O操作(例如非阻塞的方式),必须使用文件描述符方式,也没有函数能对流进行这类操作。

    • 联系
      流给用户程序提供了更高一级的(功能更强大,使用更简化)的I/O接口,它处在文件描述符方式的上层,也就是说,流函数是通过文件描述符函数来实现的。

  • 相关阅读:
    53. Maximum Subarray
    64. Minimum Path Sum
    28. Implement strStr()
    26. Remove Duplicates from Sorted Array
    21. Merge Two Sorted Lists
    14. Longest Common Prefix
    7. Reverse Integer
    412. Fizz Buzz
    linux_修改域名(centos)
    linux_redis常用数据类型操作
  • 原文地址:https://www.cnblogs.com/Jimmy1988/p/7479856.html
Copyright © 2011-2022 走看看