Linux内核中设置了一组用于实现各类系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看linux命令手册,系统调用和普通的函数调用十分相像。区别仅仅在于,系统调用由操作系统核心提供,运行于核态度;而普通的函数调用由函数库或用户自己提供,运行于用户态。
随Linux核心还提供了一些C语言函数库,这种库对系统调用进行了一些包装和扩充,由于这种库函数与系统调用的关系十分紧密,所以习惯上把这种函数称作为系统调用。
2.linux进程的运行状态
当应用程序进行系统调用的时侯,进程运行状态会发生变化,进程会从运行态变为内核态,当调用完成后,则从内核态变为运行态。
二、UNIX系统调用的标准
POSIX表示可移植操作系统插口(PortableOperatingSystemInterfaceofUNIX,简写为POSIX),POSIX标准定义了操作系统应当为应用程序提供的插口标准,是IEEE为要在各类UNIX操作系统上运行的软件而定义的一系列API标准的统称,其即将尊称为IEEE1003,而国际标准名称为ISO/IEC9945。
三、标准IO和文件IO
对于操作系统而言,I/O操作可以分为两类,一类是带缓存的IO,又称为标准IO(C标准库中提供了标准IO库,即stdio),它实现了跨平台的用户缓存解决方案。另一类是Unix/Linux下的文件IO,又称直接IO,即文件访问机制不经过操作系统内核的缓存,数据直接在c盘和应用程序地址空间进行传输。相对而言,直接IO效率更高。
操作标准IO文件IO
打开
fopen、freopen、pdopen
open
关掉
fclose
close
读
getc、fgetc、getchar、fgets、gets、fread
read
写
putc、fputc、putchar、fputs、puts、fwrite
write
1.标准IO
标准I/O是ANSIC构建的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性。标准IO在系统调用的上一层多加了一个缓冲区,也为此引入了流的概念,在UNIX/Linux下表示为FILE*(并不限于UNIX/Linux,ANSIC都有FILE的概念),FILE实际上包含了为管理流所须要的所有信息:实际I/O的文件描述符linux编程 系统io,指向流缓存的表针(标准I/O缓存,由malloc分配,又称为用户态进程空间的缓存,区别于内核所设的缓存),缓存宽度,当前在缓存中的字节数,出错标志等。标准I/O对每位I/O流手动进行缓存管理linux vi命令,它提供了三种类型的缓存:
全缓存。当塞满标准I/O缓存后才执行I/O操作。c盘上的文件一般是全缓存的。
行缓存。当输入输出遇见新行符或缓存满时,才由标准I/O库执行实际I/O操作。stdin、stdout一般是行缓存的。
无缓存。相当于read、write了。stderr一般是无缓存的,由于它必须尽早输出。
在linux的缓存IO机制中,操作系统会将IO的数据缓存在文件系统的页缓存(pagecache)中,也就是说,数据会先被拷贝到操作系统内核的缓存区中,之后就会从操作系统内核的缓存区拷贝到应用程序的地址空间。标准I/O库在关掉流的时侯手动释放缓存。另外,也可以使用函数fflush()将流所有未写的数据送入(刷新)到内核(内核缓冲区),fsync()将所有内核缓冲区的数据讲到文件(c盘)。第一次调用带缓存的文件操作函数时,标准库会手动分配显存而且读出一段固定大小的内容储存在缓存中。所以之后每次的读写操作并不是针对硬碟上的文件直接进行的,而是针对显存中的缓存的。何时从硬碟中读取文件或则向硬碟中写入文件有标准库的机制控制。实际上,标准IO最终还是通过调用系统提供的不带缓存的IO实现的(每次read/write都进行一次系统调用),标准IO的引入,防止了频繁的系统调用,降低了系统资源消耗,提升了IO效率。
以fgetc/fputc为例,当用户程序第一次调用fgetc读一个字节时,fgetc函数可能通过系统调用步入内核读1K字节到I/O缓冲区中,之后返回I/O缓冲区中的第一个字节给用户,把读写位置指向I/O缓冲区中的第二个字符,之后用户再调fgetc,就直接从I/O缓冲区中读取,而不须要进内核了,当用户把这1K字节都读完以后,再度调用fgetc时,fgetc函数会再度步入内核读1K字节到I/O缓冲区中。在这个场景中用户程序、C标准库和内核之间的关系如同在“MemoryHierarchy”中CPU、Cache和显存之间的关系一样,C标准库之所以会从内核预读一些数据放到I/O缓冲区中,是希望用户程序随即要用到这种数据,C标准库的I/O缓冲区也在用户空间,直接从用户空间读取数据比进内核读数据要快得多。
另一方面,用户程序调用fputc一般只是讲到I/O缓冲区中,这样fputc函数可以很快地返回,倘若I/O缓冲区写满了,fputc就通过系统调用把I/O缓冲区中的数据传给内核,内核最终把数据写回c盘或设备。有时侯用户程序希望把I/O缓冲区中的数据立即传给内核,让内核写回设备或c盘,这称为Flush操作,对应的库函数是fflush,fclose函数在关掉文件之前也会做Flush操作。
标准IO具有以下优点:
使用了操作系统内核缓冲区,在一定程度上分离了应用程序空间和实际的化学设备。降低了直接读盘次数,提升性能。当应用程序尝试读取某块数据的时侯,假如这块数据早已储存在了页缓存中,这么这块数据就可以立刻返回给应用程序,而不须要经过实际的化学读盘操作。其实,假如数据在应用程序读取之前并未被储存在页缓存中,这么就须要先将数据从c盘读到页缓存中去。对于写操作来说,应用程序也会将数据先讲到页缓存中去,数据是否被立刻讲到c盘起来取决于应用程序所采用的写操作机制:假如用户采用的是同步写机制(synchronouswrites),这么数据会立刻被写回到c盘上,应用程序会仍然等到数据被写完为止;假如用户采用的是延后写机制(deferredwrites),这么应用程序就完全不须要等到数据全部被写回到c盘,数据只要被讲到页缓存中去就可以了。在延后写机制的情况下linux编程 系统io,操作系统会定期地将置于页缓存中的数据刷到c盘上。与异步写机制(asynchronouswrites)不同的是,延后写机制在数据完全讲到c盘上的时侯不会通知应用程序,而异步写机制在数据完全讲到c盘上的时侯是会返回给应用程序的。所以延后写机制本身是存在数据遗失的风险的,而异步写机制则不会有这方面的担忧。2.文件IO
文件I/O称之为不带缓存的IO(unbufferedI/O)。不带缓存指的是每位read,write都调用内核中的一个系统调用。也就是通常所说的低级I/O——操作系统提供的基本IO服务,与os绑定,特定于linix或unix平台。
文件I/O又称为低级c盘I/O,遵守POSIX相关标准。任何兼容POSIX标准的操作系统上都支持文件I/O。标准I/O被称为中级c盘I/O,遵守ANSIC相关标准。只要开发环境中有标准I/O库,标准I/O就可以使用。(Linux中使用的是GLIBC,它是标准C库的超集。除了包含ANSIC中定义的函数,还包括POSIX标准中定义的函数。因而,Linux下既可以使用标准I/O,也可以使用文件I/O)。
通过文件I/O读写文件时,每次操作还会执行相关系统调用。这样处理的益处是直接读写实际文件,益处是频繁的系统调用会降低系统开支,标准I/O可以看成是在文件I/O的基础上封装了缓冲机制。先读写缓冲区,必要时再访问实际文件,因而降低了系统调用的次数。
文件I/O中用文件描述符表现一个打开的文件,可以访问不同类型的文件如普通文件、设备文件和管线文件等。而标准I/O中用FILE(流)表示一个打开的文件,一般只拿来访问普通文件。