用戶態與內核態 & 文件流與文件描述符 簡介

用戶態和內核態

程序代碼的依賴和調用關係以下圖所示:
markc++

  • Lib:標準ASCI C函數,幾乎全部的平臺都支持該庫函數,所以依賴該庫的程序可移植性好;
  • System Function:系統調用函數,與系統內核進行交互,不一樣平臺具有不一樣的函數接口,所以可移植性較差

區分用戶態和內核態主要是因爲系統資源的有限性,不能無限制的隨意分配給用戶使用,必須由系統進行統一管理程序員

  • User mode:不能直接對系統資源進行訪問,若是要操做系統資源,必須轉化爲內核態
  • Kernel mode:管理系統資源,可直接對系統資源進行控制和訪問

內核爲用戶提供了統一的API供其使用,不一樣的系統的API接口不一樣,爲了便於代碼的移植,出臺了POSIX標準,類Unix系統(Unix、Linux、BSD、SunOS等)均支持該標準。vim

文件流與文件描述符

  • 問題
    由上圖咱們可看到,每執行一次系統調用,都要涉及到CPU狀態的切換,即從用戶態切換到內核態,即從用戶空間切換到內核空間,實現上下文切換的過程,會消耗至關一部分的CPU資源,所以頻繁的磁盤訪問對程序的執行效率將形成很大影響。數組

  • 解決方案
    爲了解決以上的難題,採用了緩衝區的概念,當對磁盤文件進行操做時,可一次性從磁盤文件中讀出大量的數據暫放到緩衝區中,之後對這部分數據的訪問就不須要再進行系統調用了;當對文件行操做後,可將處理後的數據暫存到輸出緩衝區,待文件緩衝區滿後,一次性寫入到磁盤。ide

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行是對該結構體的定義,咱們打開瞅瞅!rest

[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接口,它處在文件描述符方式的上層,也就是說,流函數是經過文件描述符函數來實現的。

相關文章
相關標籤/搜索