Linux环境编程导引

计算机系统硬件组成

总线

贯穿整个系统的一组电子管道称为总线, 分为:

片内总线

系统总线

数据总线DB

地址总线AB

控制总线CB

外部总线

I/O设备

I/O设备是系统与外界联系的通道

键盘鼠标是输入设备,显式器是输出设备,磁盘既是输入设备也是输出设备,输入输出是相对于内存来说的。

内存

内存是一个重要的部件,它是与CPU进行沟通的桥梁。它用来存放程序以及程序要处理的数据,磁盘中的程序要加载到内存才能运行。

处理器

中央处理器(CPU),简称处理器。

CPU主要有运算器、控制器、寄存器构成

取指: PC, IR

译码: 指令译码器, RISC, CISC

执行: ALU

写回: -> 内存

跳转: JMP

系统结构图

DMA传输

DMA (直接访问内存)传输将数据从一个地址空间复制到另外一个地址空间的一种技术。当 CPU 初始化这个传输动作时,传输动作本身是由 DMA 控制器 来实行和完成, 而CPU可以继续去完成其他的工作, CPU仅在传输动作的开始和结束的时候参与数据传输的控制。 典型的例子就是移动一个外存的区块到芯片内部的内存区。像是这样的操作并没有让处理器工作拖延,反而可以使CPU重新去处理其他的工作。在实现DMA传输时,是由DMA控制器直接掌管总线。

操作系统

什么是操作系统

操作系统是”有效地管理计算机系统中的资源,合理地管理计算机系统的工作流程,方便用户使用”的程序的集合。

操作系统三个基本抽象

操作系统拥有三个基本抽象概念: 进程、虚拟存储器和文件

文件是对I/O设备的抽象表示,虚拟存储器是对主存和磁盘I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示。

进程

进程是操作系统对正在运行的程序的一种抽象。一个系统可以运行多个进程,而每个进程好像在独占使用硬件。

进程上下文切换

虚拟存储器

虚拟存储器为每个进程提供了一个大的、一致的、私有的地址空间;

它将内存看成是存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在主存与磁盘中来回交换数据。

为每个进程提供一致的地址空间,简化了存储管理,保护每个进程的地址空间不被其他进程破坏。

进程虚地址空间

文件

文件是一系列的字节序列,它向应用程序提供了一个统一的视角,来看待系统中各式各样的I/O设备。

虚拟文件系统VFS

虚拟文件系统是内核实现的一种架构,为用户空间提供统一的文件操作接口,即文件系统调用。它在内核内部为不同的真实文件系统提供一致的抽象接口。

用户通过系统调用与内核中的虚拟文件系统交互,进而操作实际的文件系统和设备。

系统编程 VS. 应用编程

系统编程

在操作系统之上利用系统调用、C库进行对系统资源进行访问。编写如apache 、gcc、gdb 等的服务应用.

系统资源包括:处理器,输入输出,进程管理,内存,设备,定时器,进程间通信,网络

应用编程

在更高层次的编程接口或者库之上构建应用程序。如android程序(android sdk)、iphone程序(iphone sdk)、QT程序设计(QT)、MFC程序设计(MFC)等。

系统调用在系统中所处的位置

所有操作系统都提供多种服务的入口点,由此程序向系统核请求服务。这些入口点被称之为系统调用(system call),

C库

这里我们所说的C库(libc),指的是标准C定义的C函数的集合。如标准输入输出函数、字符串处理函数、动态存储分配函数、日期时间函数、数学函数等。

GNU发布的libc称为glibc.

系统调用与C库关系

系统调用与C库从形式上来看都C函数;

但C库函数有些是调用系统调用来实现的,比如说malloc、free调用brk,printf调用write系统调用,而有些函数不需要任何系统调用,比如abs(fabs)、strcpy、atoi等,因为它并不是必需要使用内核服务;

因此系统调用通常提供的是最小界面,而C库函数通常提供更复杂的功能。

内核如何处理系统调用

内核通过软中断的方式实现系统调用, 每个系统调用被赋予一个系统调用号, 在i386平台上,执行一个系统调用需要通过 INT 0x80 指令来完成, 从用户态切换到核心态.

寄存器eax存放系统调用号, 寄存器ebx、ecx、edx、esi、edi存储系统调用参数,对于超过5个参数的系统调用,用一个寄存器(如ebx)指向用户空间的某个缓存, 该缓存存储所有系统调用的参数(可以多于5个)。

错误处理

在系统编程中通常通过函数返回值来表示错误(一般-1代表函数执行出错),并通过特殊变量errno来描述。

errno这个全局变量在 errno.h 头文件中声明如下:extern int errno;

错误处理函数:perror, strerror;

//示例

int main()
{
    int ret = close(10);
    /*
        if (ret == -1)
        {
            perror("close error");
        }
    */
    if (ret == -1)
    {
        fprintf(stderr, "close error with message: %s, errno = %d\n",
                strerror(errno), errno);
    }

    return 0;
}

常见错误代码


E2BIG


参数列表太长


EACCESS


权限不足


EAGAIN


重试


EBADF


错误的文件描述符


EBUSY


设备或资源忙


ECHILD


无子进程


EDOM


数学参数不在函数域内


EEXIST


文件已存在


EFAULT


地址错误


EFBIG


文件太大


EINTR


系统调用被中断

//常见错误代码打印程序

int main()
{
    for (int i = 0; i < 140; ++i)
    {
        errno = i;
        cout << "errno " << i << ": " << strerror(errno) << endl;
    }
    return 0;
}
时间: 2024-08-08 13:48:07

Linux环境编程导引的相关文章

Linux环境编程之共享内存区(一):共享内存区简介

Spark生态圈,也就是BDAS(伯克利数据分析栈),是伯克利APMLab实验室精心打造的,力图在算法(Algorithms).机器(Machines).人(People)之间通过大规模集成,来展现大数据应用的一个平台,其核心引擎就是Spark,其计算基础是弹性分布式数据集,也就是RDD.通过Spark生态圈,AMPLab运用大数据.云计算.通信等各种资源,以及各种灵活的技术方案,对海量不透明的数据进行甄别并转化为有用的信息,以供人们更好的理解世界.Spark生态圈已经涉及到机器学习.数据挖掘.

Linux环境编程之共享内存区(二):Posix共享内存区

现在将共享内存区的概念扩展到将无亲缘关系进程间共享的内存区包括在内.Posix提供了两种在无亲缘关系进程间共享内存区的方法: 1.内存映射文件:由open函数打开,由mmap函数把得到的描述符映射到当前进程地址空间中的一个文件.(上一节就是这种技术) 2.共享内存区对象:由shm_open打开一个Posix名字(也许是在文件系统中的一个路径名),所返回的描述符由mmap函数映射到当前进程的地址空间.(本节内容) Posix共享内存区涉及以下两个步骤要求: 1.指定一个名字参数调用shm_open

Linux环境编程之文件I/O(六):文件属性

引言: 在Linux中使用ls -l filename命令查看filename的属性时,会列出文件的9种属性,例如:ls -l /etc/fstab -rw-r--r-- 1 root root 1102 2013-10-12 02:33 /etc/fstab 从左到右分别是类型与权限.文件个数.该文件或目录的拥有者.所属的组.文件大小.创建时间.文件名 以上这些文件属性的信息,都存放在一个stat的结构体中.下面就来分析一下这个结构体. 要想查看一个文件的stat结构体,可以通过stat类函数

Linux环境编程之文件I/O(四):文件I/O的数据结构

(一) Linux系统支持不同进程间共享打开的文件.内核使用三种数据结构表示打开的文件:进程表项.文件表项.v节点表. 1.进程表项:每个进程在进程表中都有一个记录项,记录项中年包含有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项.与每个文件描述符相关联的是: a.文件描述符标志 b.指向一个文件表项的指针 2.内核为所有打开文件维持一张文件表.每个文件表项包含: a.文件状态标志,如读写.添加.同步和非阻塞等. b.当前文件偏移量 c.指向该文件v节点表项的指针 3.每个打开的文

Linux环境编程之进程(一):main函数调用、进程终止以及命令行参数和环境表

(一)main函数调用 main函数作为程序运行时的入口函数,它是如何被调用的呢?首先必须清楚一点,main函数也是一个函数,它只有被调用才能够执行.其实,在执行可执行程序时,在调用main函数之前,内核会先调用一个特殊的启动例程,将此启动例程作为可执行程序的起始地址.启动例程是如何作为可执行程序的起始地址的?这是由链接编译器设置的,而链接编译器则是由C编译器(如gcc编译器)调用的.启动例程作为可执行程序的起始地址主要做哪些工作呢?启动例程从内核取得命令行参数和环境变量值,以此来为main函数

Linux环境编程之文件I/O(七):目录文件及操作

什么是数据结构? 数据结构是相互之间存在一种或多种特定关系的数据元素的集合. 还有一些概念(数据.数据元素.数据项.数据对象.数据类型...) 传统上,我们把数据结构分为逻辑结构和物理结构. 逻辑结构:是指数据对象中数据元素之间的相互关系,也是我们今后最需要关注和讨论的问题. 物理结构:是指数据的逻辑结构在计算机中的存储形式. 逻辑结构分为以下四种: 1.集合:集合结构中的数据元素除了同属于一个集合外,之间没有任何关系. 2.线性结构:元素之间一对一. 3.树形结构:一对多. 4.图形结构:多对

Linux环境编程之文件I/O(五):fcntl函数

引言: 对于一个普通的文件,我们可以想到的对它的操作有,读取文件的内容.写数据到文件中,这些都是前面提到的read.write函数的作用.除此之外,还可以获取文件的其他性质,并对这些性质进行修改,比如文件的描述符.文件描述符标记.文件状态标志等等.这些对文件性质的修改就由fcntl函数完成. 函数介绍: #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 参数: fd:

Linux环境编程之文件I/O(二):文件的打开与关闭

(一) Linux系统中,要对一个文件进行任何操作,必须首先获得它的文件描述符.而获得文件描述符的方式就是利用open/creat函数打开/创建该文件,open/creat函数返回文件描述符. #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, in

Linux环境编程之进程(六):进程组

进程组 每个进程除了有一个进程ID之外,还属于一个进程组.进程组是一个或多个进程的集合.每个进程组有一个唯一的进程组ID.进程组ID类似于进程ID--它是一个整数,并可存放在pid_t数据类型中.函数getpgrp返回调用进程的进程组ID. 每个进程组都可以有一个组长进程.组长进程的标识是,其进程组ID等于其进程ID.组长进程可以创建一个进程组,创建该组中的进程,然后终止.只要在某个进程组中有一个进程存在,则进程组就存在,这与其组长进程是否终止无关.从进程组创建开始到其中最后一个进程离开为止的时