虚拟地址空间原理

image-20210924210416032

学习视频

Linux 为每个运行程序(进程) 操作系统都会为其分配一个 0 ~ 4G 的地址空间 (虚拟地址空间)

  1. 进程: 正在运行的程序
  2. Linux 下 可执行文件格式: ELF
  3. 格式主要包含3个段
    1. 其他段:
      1. 只读数据段
      2. 符号段
  4. 通过这一节,你应该知道,一个内存管理系统至少应该做三件事情:
    • 第一,虚拟内存空间的管理,每个进程看到的是独立的、互不干扰的虚拟地址空间;
    • 第二,物理内存的管理,物理内存地址只有内存管理模块能够使用;
    • 第三,内存映射,需要将虚拟内存和物理内存映射、关联起来。

7_库函数与系统函数的关系

4_C库IO函数工作流程

linux 文件读写 API

学习视频

目录操作

  • 目录操作 opendir readdir closedir

cpp 的 api

  • 函数 open close read write lseek

文件描述符

文件描述符和进程的原理

5_pcb和文件描述符

每一个进程都有一个 PCB 【进程控制块】

  1. 进程控制块里面有一个 文件描述符表

    1. 文件描述符表 是基于一个 长度为 1024的数组俩实现的

      1. 前3个文件描述符 分别是

        1. 0 表示 表示输入
        2. 1 表示标准输出
        3. 2 表示标准错误输出
        4. 其他的话待定
         	1. 一般就是 调用 open 函数 就会返回一个 fd
              	1. 这个 fd 就存在 PCB 的文件描述符表数组里面
        
      2. 前3个默认被占用,后面的 是给 系统打开文件的 api 存 fd 用

        • 每打开一个新文件就占用一个文件描述符【而且使用的是空闲的最小的一个文件描述符】

open函数解释

  1. open/close

    • 函数原型:
      • int open(const char* pathname, int flags);
      • int open(const char* pathname,int flags, mode_t mode);
      • 参数:
        • flags:
          • 必选项: O_RDONLY, O_WRONLY, O_RDWR
          • 可选:
            • 创建文件: O_CREAT
            • 如果文件存在, 返回 -1
            • 追加文件: O_APPEND
            • 文件截断: O_TRUNC
            • 设置非阻塞: O_NONBLOCK
        • mode
  2. read

    • 函数原型: ssize_t read(int fd,void* buf, size_t count);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdio>
#include <unistd.h>


using namespace std;



int main(void) {


    int fd = -1;
    fd = open("app.txt",O_RDWR|O_CREAT, 0777);//读,写执行
    if (fd == -1 ) {
         puts("打开文件失败");
//        exit(1);
    }

    close(fd);
    puts("打开文件成功");


    return 0;
}




/*
-rwxrwxr-x 1 lyr lyr     0 Sep 24 22:20 app.txt

最后的结果其实是 775 不是 777
因为 他的结果其实是 mode & ~umask
这个是 linux 给的一个保护作用
umask 输出 其实是 0002
0002 + 775 = 777


*/

文件操作相关的函数

根据文件描述符来操作文件的状态 – #include <fcntl.h>

函数原型 int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock);

复制一个现有的描述符 – cmd F_DUPFD 获得/设置文件描述符标记 – cmd F_GETFD F_SETFD 获得/设置文件状态标记 – cmd F_GETFL 只读打开 O_RDONLY 只写打开 O_WRONLY 读写打开 O_RDWR 执行打开 O_EXEC 搜索打开目录 O_SEARCH 追加写 O_APPEND 非阻塞模式 O_NONBLOCK F_SETFL 可更改的几个标识 O_APPEND O_NONBLOCK 获得/设置异步I/O所有权 – cmd F_GETOWN F_SETOWN 获得/设置记录锁 – cmd F_GETLK F_SETLK F_SETLKW

阻塞读取终端数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>

using namespace std;


int main(void) {
   #define N  45
   char buf[N];

   int n;
   n = read(STDIN_FILENO,buf, N);
   if( n< 0 ) {
        perror("read stdin_error");
        exit(1);
   }
   write(STDOUT_FILENO,buf, n);
   return 0;
}

非阻塞读取数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>



using namespace std;
#define MSG_TRY  "try to read s:=\n"

int main(void) {
#define BufSize 10
    char buf[BufSize];
    int fd,n;
    //非阻塞读,没读取到数据,立刻返回
    fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
    if (fd < 0)
    {
        perror(" open fail /dev/tty");
        exit(1);
    }
tryRead:
    n = read(fd, buf, BufSize);
    if ( n < 0 ) {
        if ( errno == EAGAIN) {
            sleep(3);
            write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
            //重新读取数据
            goto tryRead;

        }
        perror("read /dev/tty");

    }

    write(STDOUT_FILENO,buf, BufSize);
    close(fd );



    return 0;
}