标签 TLPI 下的文章

在堆上分配内存

进程可以通过增加堆的大小来分配内存,所谓堆是一段长度可变的连续虚拟内存,始于进程的未初始化数据段末尾,随着内存的分配和释放而增减。通常将堆的当前内存边界称为“program break”。

调整program breakbrk()sbrk()

改变堆的大小其实就是命令内核改变进程program break的位置,最初program break正好位于未初始化数据段末尾之后。
program break位置抬升后,程序可以访问新分配区域内的任何内存地址,而此时物理内存尚未分配。内核会在进程首次试图访问这些虚拟内存地址时自动分配新的屋里内存页。


- 阅读剩余部分 -

进程和程序

  • 进程是一个可执行程序的实例。
  • 程序是包含了一系列信息的文件,这些信息描述了如何在运行时创建一个进程,所包含的内容如下所示:

    • 二进制格式标识
    • 机器语言指令
    • 程序入口地址
    • 数据
    • 符号表及重定位表
    • 共享库和动态链接信息
    • 其他信息
  • 可以用一个程序来创建许多进程,或者反过来说,许多程序运行的可以是同一程序
  • 进程是由内核定义的抽象的实体,并为该实体分配用以执行程序的各项系统资源
  • 从内核角度看,进程由用户内存空间和一系列内核数据结构组成,其中用户内存空间包含了程序代码及代码所使用的变量,而内核数据结构则用于维护进程状态信息。

- 阅读剩余部分 -

原子操作和竞争条件

原子操作:

  1. 将某一系统调用所要完成的各个动作为不可中断的操作,一次性加以执行。
  2. 所有系统调用都是以原子操作方式执行的。
  3. 原子性是某些操作得以圆满成功的关键所在。特别是它规避了竞争状态(如情形:操作共享的资源的两个进程或线程,其结果取决于一个无法预期的顺序,即这些进程获得CPU使用权的先后相对顺序)

以独占方式创建一个文件

当同时指定O_EXCLO_CREAT作为open()的标志位时,如果要打开的文件已然存在,则open()将返回一个一个错误,这提供了一种机制:保证进程是打开文件的创建者。对文件是否存在的检查和创建文件属于同一原子操作

向文件尾部追加数据

多个进程同时向一个文件尾部追加数据,为避免进程间互相覆盖数据,应在打开文件时加入O_APPEND标志可以保证原子操作。

- 阅读剩余部分 -

概述

  • 所有执行I/O操作的系统调用都以文件描述符,一个非负整数的,来指代打开的文件。
  • 文件描述符用以表示所有类型的已打开文件,包括管道、FIFO、socket、终端、设备和普通文件。
  • 针对每个进程,文件描述符都自成一套。
  • 文件描述符012表示标准输入标准输出标准错误,这三个文件描述符在进程中始终是打开的
  • 下面介绍执行文件I/O操作的4个主要系统调用:

    • fd = open(pathname, flags, mode)函数打开pathname所标识的文件,并返回文件描述符,用以在后续函数调用中指代打开的文件
    • numread = read(fd, buffer, count)调用从fd所指代的打开文件中读取至多count字节的数据,并存储到buffer
    • numwritten = write(fd, buffer, count)调用从buffer中读取多达count字节的数据写入由fd所指代的已打开文件中
    • status = close(fd)在所有输入/输出操作完成后,调用close(),释放文件描述符fd以及与之相关的内核资源

- 阅读剩余部分 -

系统调用

  • 系统调用是受控的内核入口,借助于这一机制,进程可以请求内核以自己的名义去执行某些动作。
  • 以应用程序编程接口(API)的形式,内核提供有一系列服务供程序访问。
  • 关于系统调用需关注一下几点:

    • 系统调用将处理器从用户态切换到核心态,以便CPU访问受到保护的内核内存
    • 系统调用的组成是固定的,每个系统调用都由一个唯一的数字来标识
    • 每个系统调用可辅之以一套参数,对用户空间与内核空间之间传递的信息加以规范。
  • 从C语言编程的角度来看,调用C语言函数库的外壳函数等同于调用相应的系统调用服务例程。

- 阅读剩余部分 -