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


第5周主要学习内容

主要学习了fopen、fread和fwrite函数,对进程函数fork()以及exec函数族、停止进程函数进行了了解学习。

一、Linux下文件的相关操作(fopen、fread、fwrite)

1.fopen函数

函数原型

#include <stdio.h>
FILE * fopen(const char * path,const char * mode);

参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。mode有下列几种形态字符串:

命令 说明
"r"或"rb" 以只读方式打开文件,该文件必须存在。
"w"或"wb" 以写方式打开文件,并把文件长度截短为零。
"a"或"ab" 以写方式打开文件,新内容追加在文件尾。
"r+"或"rb+"或"r+b" 以更新方式打开(读和写)
"w+"或"wb+"或"w+b" 以更新方式打开,并把文件长度截短为零。
"a+"或"ab+"或"a+b" 以更新方式打开,新内容追加在文件尾。

返回值:文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno中。

2.fread函数

函数原型

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 参数解释:
    • ptr: 指向一块存储空间,用来存放本次读取到的数据
    • size: 表示一次读取的数据单元大小
    • nmemb: 本次读取多少个数据元素(也可以叫一个数据单元,我不知是否准确)
    • stream: 将要读取的文件流
  • 返回值:
    • 如果读取成功,返回 nmemb,即返回读取到的元素个数(不是读取的字符个数)
    • 如果遇到文件结束,返回实际读取到的元素个数,可能小于 nmemb
    • 如果失败,返回0

3.fwrite函数

函数原型

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 参数解释:
    • ptr: 指向一块存储空间,用来存放本次写入的数据
    • size: 表示一次写入的数据单元大小
    • nmemb: 表示写入的次数
    • stream: 目标文件指针
  • 返回值:
    • 成功时fwrite返回的值与nmemb相等
    • 若小于nmemb表示出错了(可以使用perror函数查看错误原因)

二、Linux下进程创建相关的系统调用

1.进程函数fork()

fork()函数用于从已存在的进程中创建一个新进程。(新进程称为子进程,原进程称为父进程)

  • fork()函数所需头文件:#include<sys/types.h> //提供类型pid_t的定义 #include<unistd.h>
  • 函数原型:pid_t fork(void)
  • fork仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
    • 在父进程中,fork返回新创建子进程的进程ID(大于0的整数);
    • 在子进程中,fork返回0;
    • 如果出现错误,fork返回-1;

在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

  • fork出错可能有两种原因:
    • 当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
    • 系统内存不足,这时errno的值被设置为ENOMEM。

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。每个进程都有一个独特(互不相同)的进程标识符process ID,可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。

2.exec函数族

在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是:

#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

  • exec函数族提供了一个在进程中启动另一个程序执行的方法。
  • Linux中使用exec函数族的两种情况:
    • 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生;
    • 如果一个进程想执行另一个程序,那么它就可以调用fork()函数新建一个进程,然后调用exec函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程。(这种情况非常普遍)

3.exit()和_exit()函数

  • exit()就是退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出,一般都用-1或者1。
  • _exit()直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。

exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O缓冲"。

_exit返回后直接返回内核,而exit要进行清除工作,那么两者到底有什么不同呢?
其实exit结束进程也是调用了_exit函数,但是它在之前做了两点:
1.调用atexit() // 注册的函数(出口函数)按ATEXIT注册时相反的顺序调用所有由它注册的函数,这使得我们可以指定在程序终止时执行自己的清理动作.例如,保存程序状态信息于某个文件,解开对共享数据库上的锁等.
2.cleanup();关闭所有打开的流,这将导致写所有被缓冲的输出,删除用TMPFILE函数建立的所有临时文件。

4.wait()和waitpid()函数

  • wait()作用:用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()就会立即返回。
  • waitpid()作用:waitpid()的作用和wait()一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能,也能支持作业控制。

实际上wait()函数只是waitpid()函数的一个特例,在Linux内部实现wait()函数时直接调用的就是waitpid()函数。

函数原型

pid_t wait (int *status)
pid_t waitpid(pid_t pid,int * status,int options)

waitpid函数提供了wait函数没有提供的三个功能:

  • waitpid等待一个特定的进程,而wait则返回任一终止子进程的状态 。
  • waitpid提供了一个wait的非阻塞版本,有时希望取得一个子进程的状态,但不想进程阻塞。
  • waitpid支持作业控制。

学习进度条

| | | | |
| -------- | :----------------😐:----------------😐:---------------: | :--------------: |
| | 代码行数(新增/累积)| 博客量(新增/累积)|学习时间(新增/累积)|重要成长|
| 目标 | 5000行 | 30篇 | 400小时 | |
| 第一周 | 100/100 | 1/1 | 10/10 |复习了vim、gcc的相关知识|
| 第二周 | 300/400 | 1/2 | 18/28 | 学习了有关gcc、gdb、静态库和动态库、Makefile的相关知识及操作|
| 第三周 | 600/1000 | 0/2 | 18/46 |学习了如何搭建Linux交叉开发环境|
| 第四周 | 1000/2000 | 1/3 | 20/66 |学习了Bootloader的配置、移植和编译|
| 第五周 | 3000/5000 | 1/4 | 30/96 |学习了fopen、fread和fwrite函数,对进程函数fork()以及exec函数族、停止进程函数进行了了解学习|

posted on 2017-05-23 17:18  愚yyy  阅读(123)  评论(0编辑  收藏  举报