用户态与内核态 & 文件流与文件描述符

栏目: C++ · 发布时间: 5年前

内容简介:区分用户态和内核态主要是由于系统资源的有限性,不能无限制的随意分配给用户使用,必须由系统进行统一管理内核为用户提供了统一的API供其使用,不同的系统的API接口不同,为了便于代码的移植,出台了POSIX标准,类Unix系统(Unix、Linux、BSD、SunOS等)均支持该标准。

用户态和内核态

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

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

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

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

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

文件流与文件描述符

  • 问题:

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

  • 解决方案:

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

用户态与内核态 & 文件流与文件描述符

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

  • 文件流:

    简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向;

    文件流用结构体表示: 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接口,它处在文件描述符方式的上层,也就是说,流函数是通过文件描述符函数来实现的。

本文永久更新链接: http://embeddedlinux.org.cn/emb-linux/kernel-driver/201904/28-8651.html


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

运营前线 2

运营前线 2

兰军 等著 / 机械工业出版社 / 2017-4 / 69.00

“运营前线”是一个系列,目前已经出版2部,与“产品前线”一样,该系列书也由资深的产品和运营专家兰军(Blues)领衔策划和写作,旨在梳理和总结国内一线互联网公司的运营方法和技巧,让所有产品人和运营人都有机会了解和学习这些大的互联网公司是如何做运营的。 这2部作品汇集了来自腾讯、阿里、百度、360、迅雷、YY、小米、爱奇艺、乐视等数十家大型互联网公司的一线运营专家的技巧和方法论。共包含9大运营......一起来看看 《运营前线 2》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具