第6章 文件处理与进程控制
在该程序中,首先使用fork()函数创建一个子进程, 然后在子进程里使用execlp()函数。从程序中可 以看到,这里的参数列表列出了在shell中使用的 命令名和选项。 将文件保存为execlp.c,使用交叉编译命令armlinux-gcc进行交叉编译: [root@localhost test]# arm-linux-gcc -o execlp execlp.c 将其下载到嵌入式系统开发板上运行该程序,运行 结果如下所示: [root@localhost test]# ./execlp execlp execlp.c proid proid.c
2、write函数
• write函数用于向打开的文件实现写入数据的操作。 写操作的位置从文件的当前位移量处开始。若磁 盘已满或超出该文件的长度,则write函数返回错 误值。 • 调用write函数所需要的头文件: • #include <unistd.h> • 其函数原型为: • ssize_t write(int fd, void *buf, size_t count); • 函数返回值为已写入数据的字节数,若返回-1则 出错。
6.1.3 read函数、write函数和 lseek函数
1、read函数
• read函数从打开的文件中读取数据。 • 调用read函数所需要的头文件: # include <unistd.h> • 其函数原型为: • ssize_t read(int fd, void *buf, size_t count); • 函数返回值为读到数据的字节数,若返回 值为0,则已经到达文件尾,若返回-1则为 出错。
2、系统调用
• 所谓系统调用是指操作系统提供给用户程 序调用的一组“特殊”接口,用户程序可 以通过这组“特殊”接口来获得操作系统 内核提供的服务。例如用户可以通过进程 控制相关的系统调用来创建进程、实现进 程调度、进程管理等。
3、文件处理
• Linux系统的文件处理,主要是指进行打开 文件、读文件、写文件及关闭文件等I/O操 作。大多数情况下,只需用到5个函数: open、read、write、lseek 和close。这 几个函数不需要经过缓冲就能立即执行, 因此,被称之为不带缓存的I/O操作,即每 一个函数都只调用内核中的一个系统调用。
3、System函数
system函数可以在一个程序的内部启动另一 个程序,从而创建一个新进程。system函 数所需要的头文件为: #include <stdlib.h> 其函数原型为: int system(const char *string);
4、进程调用的应用示例
【例6-8】设已有C语言的源程序Hello.c,现 编写一个程序,在程序中自动编译Hello.c, 并运行编译后的执行文件Hello。 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 int main() 5 { /* 调用system函数编译命令 */ 6 system("gcc -o Hello Hello.c");
【例6-6】应用execlp函数列出当前目录下的所有文件。
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 int main() 5 { 6 if (fork() == 0) 7 { 8 int ret; 9 /*调用execlp()函数,这里相当于调用了"ls -l"命令*/ 10 ret = execlp("ls", "ls", "-l", NULL); 11 } 12 return 0; 13 }
【例6-4】 获取当前进程的进程号PID。 1 2 3 4 5 6 7 #include <stdio.h> #include <unistd.h> int main() { printf(“PID = %d \n”, getpid()); return 0; }
将程序保存为proID.c,使用交叉编译命令 arm-linux-gcc进行交叉编译: [root@localhost test]# arm-linux-gcc -o proID proID.c 将其下载到嵌入式系统开发板上运行该程序: [root@localhost ex5]# ./proID PID = 3061 注意,每次执行结果都不一定相同。
2、exec函数族
在嵌入式Linux中并没有exec函数,而是有六种以 exec开头的函数,统称exec函数: #include <unistd.h> 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[]);
3、创建进程
• 创建新进程的函数为fork( ),其函数原型为: • pid_t fork(void); • fork调用失败则返回-1,调用成功的返回值为进 程号。 • fork函数被调用后会返回两次。一次是在父进程 中返回,另一次是在子进程中返回,这两次的返 回值是不一样的。在子进程中返回0值,而在父进 程中返回子进程的进程号PID。 • 在执行fork()之后,同一进程有两个拷贝都在运行, 也就是说,子进程具有与父进程相同的可执行程 序和数据(简称映像)。
从上述运行结果中可以看出fork函数的特点,概括 起来就是“调用一次,返回两次”,在父进程中调 用一次,在父进程和子进程中各返回一次。第一次 的返回值PID = 0是在子进程中返回的进程号,第 二次的返回值PID = 4138是在父进程中返回子进程 的进程号。
6.2.2 进程控制
1、调用exec函数运行执行程序
4、示例
• 【例6-2】创建一新文件,然后对此文件进 行读写操作。 • 设计思路与分析: • (1)创建新文件 • (2)将指定内容写进文件 • (3)读取文件内容 • (4)关闭文件
6.2 进程与进程控制
6.2.1 进程
1、什么是进程
• 进程是一个具有独立功能的程序的一次动态执行 过程。简言之,进程就正在执行的程序。 • 例如,打开一个Windows资源管理器是在执行一 个进程,运行一个浏览器阅读WEB网页也是在执 行一个进程等。
6.1.2
open函数和close函数
1、open函数
• open函数用于打开或创建文件。 • 调用open函数所需要的头文件如下: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> • 其函数为: • int open(const char *pathname, int oflag, int perms ) ; • 函数返回值:若文件打开成功则返回文件 描述符,若出错则返回-1。
第6章 文件处理与进程控制
本章要点
1、文件描述符的概念 2、系统调用的基本概念 3、文件读写等处理方法 4、进程的概念 5、进程控制与进程间的通信 6、嵌入式Linux中对串口的操作
6.1嵌入式Linux的文件处理
6.1.1
文件描述符及文件处理
• 1、文件及文件描述符 • 由于在Linux下设备和目录都看作是文件, 因此,Linux中的文件有4种类型:普通文 件、目录文件、链接文件和设备文件。 • Linux的内核利用文件描述符访问文件。文 件描述符是非负整数,它是一个索引值, 并指向内核中每个进程打开文件的记录表。 当打开一个现存文件或新建一个文件时, 内核会向进程返回一个文件描述符。当读 写文件时,也需要使用文件描述符来指定 待读写的文件。
【例6-5】创建一个进程。
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 int main() 5 { 6 pid_t pid; 7 pid = fork( ); 8 printf(“PID = %d \n”, pid); 9 return 0; 10 }
2、close函数
• close函数用于关闭一个打开的文件,所需 要的头文件为: • #include <unistd.h> • 其函数为: • int close(int fd); • 函数返回值:若成功为0,若出错为-1。 • 关闭文件函数close的参数fd为文件描述符。
3、示例
• 【例6-1】用可读写方式新建源自打开)一个 文件。 详见教材• 为了让子进程能运行另外的执行程序,需要用到 exec函数。当进程调用一种exec函数时,该进程 的用户空间代码和数据完全被新程序替换,从新 程序的启动例程开始执行。 • exec函数提供了一个在进程中启动另一个程序执 行的方法。它可以根据指定的文件名或目录名找 到可执行文件,并用它取代原调用进程的数据段、 代码段和堆栈段,在执行完后,原调用进程的内 容除了进程号外,其他全部被新的进程替换了。 也就是说,调用exec并不创建新进程,所以调用 exec前后该进程的进程号PID并未改变。