2014025692 《嵌入式系统程序设计》第五周学习总结

2014025692 《嵌入式系统程序设计》第五周学习总结

本周主要在上周学习的基本的C语言文件操作函数的基础上,学习了标准I/O编程。另外,还学习了Linux操作系统的进程及其控制编程相关的知识。

一、标准I/O编程

write()、read() 等这些函数是接本的 I/O 控制,没有缓存,系统调用是操作系统直接提供的函数接口,因此运行系统调用时,过程非常繁琐,Linux 必须从用户态切换到内核态,执行相应的请求,然后再返回到用户态。而标准 I/O 处理与之相比优势在于拥有缓存,减少系统调用的次数,从而提高程序的效率。

1、3种缓冲存储

  (1)全缓冲:当填满标准 I/O 缓存后才进行实际I/O 操作。存放在磁盘上的文件通常是由标准I/O 库实施全缓冲的。在一个流上执行第一次I/O 操作时,通常调用malloc()就是使用全缓冲。

  (2)行缓冲:当在输入和输出中遇到行结束符时,标准 I/O 库执行I/O 操作。标准输入(scanf())和标准输出(read())使用的就是行缓冲。

  (3)不带缓冲:标准 I/O 库不对字符进行缓冲。如果用标准I/O 函数写若干字符到不带缓冲的流中,则相当于用系统调用write()函数将这些字符全写到被打开的文件上。

2、基本操作标准 I/O 编程函数

对文件进行基本操作最常用的函数便是 fopen()、fclose()、fwrite()和fread()四个函数了, 在调用它们前必须引入 stdio.h 头文件,以下便是它们的函数原型、参数机返回值。

(一)fopen()

该函数可以指定打开文件的路径和模式。

  (1)函数原型:FILE * fopen(const char * path, const char * mode)
  (2)函数参数:

参数 含义
path 包含要打开的文件路径及文件名
mode 文件打开状态
其中 mode 可以定义打开文件的访问权限等,可选参数如下(在每个选项中加入 b 字符用来告诉函数库打开的文件为二进制文件):
参数 作用
r/rb 打开只读文件,该文件必须存在
r+/r+b 打开可读写的文件,该文件必须存在
w/wb 打开只写文件,若文件存在则文件长度清为0,即会擦写文件以前的内容。若文件不存在则创建该文件
w+/w+b 打开可读写文件,若文件存在则文件长度清为0,即会擦写文件以前的内容。若文件不存在则创建该文件
a/ab 以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留
a+/a+b 以附加方式打开可读写的文件。若文件不创建,则会建立该文件;如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留
(3)函数返回值:
成功:指向 FILE 的指针
失败:NULL

(二)fclose()

该函数可以将缓冲区内的数据全部写入到文件中,并释放系统所提供的文件
资源。

  (1)函数原型:int fclose(FILE * stream)
  (2)函数参数:

参数 含义
stream 已打开的文件指针
(3)函数返回值
成功:0
失败:EOF

(三)fwrite()

该函数数用于对指定的文件流进行写操作。

  (1)函数原型:size_t fwrite(const void * ptr,size_t size, size_t nmemb, FILE * stream)
  (2)函数参数:

参数 含义
ptr 存放写入记录的缓冲区
size 写入的记录大小
nmemb 写入的记录数
stream 要写入的文件流
(3)函数返回值
成功:返回实际写入的记录数目
失败:EOF

(四)fread()

在文件流被打开之后,该函数可对文件流进行读写等操作,其中读操作

  (1)函数原型:size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)
  (2)函数参数:

参数 含义
ptr 存放读入记录的缓冲区
size 读取的记录大小
nmemb 读取的记录数
stream 要读取的文件流
(3)函数返回值
成功:返回实际读取到的 nmemb 数目
失败:EOF

二、Linux进程

进程是一个程序的一次执行的过程,同时也是源分配的最小单元。进程与程序的区别在于进程是动态的,而程序是静态的。

1、进程的运行状态

进程有三种运行状态,分别为等待、就绪和执行,它们的转换关系如下:

2、Linux下进程管理

可用Shell命令对进程进行简单的管理操作,最常用的命令如下:

命令 含义
ls等shell命令 启动相应的进程
ps 查看系统中的进程
ps -ef 查看正在活动的进程
top 动态显示系统中的进程(q退出)

3、Linux进程控制编程

(一)fork()

fork()函数用于从已存在的进程中创建一个新进程。新进程成为子进程,原进程为父进程。因为子进程为父进程的复制品,所以子进程除了独有的进程号、资源使用和计时器等,其余的全部与父进程一致。

  (1)函数所需头文件:sys/types.h、unistd.h
  (2)函数原型:pid_t fork(void)
  (3)函数返回值:

返回值 含义
0 子进程
子进程ID(大于0的整数) 父进程
-1 出错
注意:
(1)父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。

(二)exec族函数

exec族函数提供了启动fork()创建的子进程的方法,有多个成员函数。

  (1)函数所需头文件:unistd.h
  (2)函数原型:

函数名 函数原型
execlp int execlp(const char *file, const char *arg, ...)
execl int execl(const char *path, const char *arg, ...)
execle int execle(const char *path, const char *arg, ..., char *const envp[])
execve int execve(const char *path, char *const argv[], char *const envp[])
(3)函数返回值:
-1:出错
(4)成员函数说明:
execlp():使用文件名在环境变量$PATH中查找可执行文件,同时使用参数列表的方式启动子进程。

execl():使用完整的文件目录来查找对应的可执行文件启动子进程,文件目录开头必须使用根目录(/)。

execle():可将环境变量添加到新建的子进程中,并启动子进程。

execve():可以通过构造指针数组的方式向子进程传递参数,并启动子进程。

(三)终止进程函数

想要终止进程时,可以调用exit(0和_exit()两个函数,它们都可以令进程会无条件地停止剩下的所有操作,清除包括PCB 在内的各种数据结构,并终止本进程的运行。在参数方面一般使用0(表示正常结束)。但它们也有些不同之处:
exit():需要引入头文件stdlib.h,它在调用exit 系统之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,也就是能将缓冲区中的信息保存或输出等操作。
_exit(0:需要引入头文件unistd.h,调用时不会检查缓冲区,直接终止进程,并清空I/O缓冲区,也就是会令缓冲区中的信息丢失。(printf()实用的是行缓冲,在没有\n的情况下,会将当前这一行的信息存入缓冲区中,不会输出)

(四)中断进程函数

由于CPU同时只能执行一个进程,有时就需要中断现在的进程,为其他进程提供CPU执行的条件,就需要调用wait()或waitpid()函数。

  (1)函数所需头文件:sys/types.h、sys/wait.h
  (2)函数原型:

函数名 函数原型
wait() pid_t wait(int *status)
waitpid() pid_t waitpid(pid_t pid, int *status, int options)
(3)函数参数:
wait():status 是一个整型指针,是该子进程退出时的状态,status 若不为空,则通过它可以获得子进程的结束状态。

waitpid():

Pid
    pid>0        只等待进程ID 等于pid 的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid()就会一直等下去
    pid=1        等待任何一个子进程退出,此时和wait()作用一样
    pid=0        等待其组ID 等于调用进程的组ID 的任一子进程
    pid<1        等待其组ID 等于pid 的绝对值的任一子进程
    
status           若不为空,则通过它可以获得子进程的结束状态

options
    WNOHANG        若由pid 指定的子进程不立即可用,则waitpid()不阻塞,此时返回值为0
    WUNTRACED      若实现某支持作业控制,则由pid 指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态
    0              同wait(),阻塞父进程,等待子进程退出

  (4)函数返回值:
wait():
    成功:已结束运行的子进程的进程号
    失败:1

waitpid():
    正常:已经结束运行的子进程的进程号
    使用选项 WNOHANG 且没有子进程退出:0
    调用出错:1
  (5)函数说明:
wait():使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则wait()就会立即返回。
waitpid():在wait()的基础上,拥有更多的选项参数,可以实现更多的功能,可以认为wait()是waitpid()的特例。

三、收获与感悟

(1)更加深入的理解了C语言对文件操作的原理及过程,体会到了标准I/O处理(fopen()、fread()等)相对于系统调用(open()、read())的简便性。
(2)加深了对进程的理解,掌握了一系列对进程错做的函数。
(3)结合wait()和waitpid()的实例,加深了对多种缓冲区的理解。
(4)学会了新的markdown语法。

四、学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 200/200 2/2 20/20
第二周 300/500 2/4 18/38
第三周 500/1000 3/7 22/60
第四周 300/1300 2/9 30/90
第五周 700/2000 3/12 60/150

五、参考资料

  • 《嵌入式应用程序设计》学习指导
posted @ 2017-05-21 21:57  舲舟聆雨  阅读(137)  评论(0编辑  收藏  举报