目录
一、文件管理:stat、access、chmod、truncate、link函数
二、进程控制:fork()、exec函数族、wait()、exit()
今天的课程先是承接了上次课程的“文件操作”相关内容,然后开始了新的内容:进程控制。
一、文件管理:stat、access、chmod、truncate、link函数
1.stat()
#include <sys/stat.h>
int stat(const char *path,struct stat *buf);
功能:用于获取文件的属性;
参数说明:*path:文件路径;
*buf:接受获取到的文件属性;文件属性存储在inode中,函数从inode结构体中获取文 件信息
返回值说明:成功:0
不成功:-1并设置errno
【案例1】使用stat函数获取文件属性,并输出文件的大小。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(){
struct stat tempSBuf;
int tempRet = 2;
tempRet = stat("a.out", &tempSBuf);
if(tempRet == -1){
perror("stat error:");
exit(1);
}//of if
printf("len = %d\n", tempSBuf.st_size);
return 0;
}//of main
运行结果如下:
2.access()
#include <unistd.h>
int access(const char *pathname, int mode);
功能:用于测试文件是否拥有某种权限;
参数说明:*pathname:文件名;
*mode:取值有4个:R_OK,W_OK,X_OK,F_OK;前面3个是测试文件是否有读、写、执行权限,最后一个测试文件是否存在。
返回值说明:成功:0,表示文件存在或具有某种权限。
不成功:-1并设置errno
3.chmod()
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
功能:用于修改文件的访问权限;
参数说明:*path:路径名;
*mode:传递修改后的权限。
返回值说明:成功:0,表示文件存在或具有某种权限;
不成功:-1并设置errno
4.truncate()
#include <sys/stat.h>
int truncate(const char *path, off_t length);
功能:用于修改文件大小,常用于扩展文件,其功能与lseek函数类似;
参数说明:*path:路径名;
*length:设置文件大小。
返回值说明:成功:0
不成功:-1并设置errno
二、进程控制:fork()、exec函数族、wait()、exit()
1.1创建进程
#include <unistd.h>
pid_t fork(void);
【案例1】使用fork函数创建一个进程,创建成功后父子进程分别执行不同的功能。
test_fork.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
pid_t tempPid;
tempPid = fork();
if(tempPid == -1){
perror("fork error");
}else if(tempPid > 0){//parent
printf("parent process, pid = %d, ppid = %d\n", getpid(), getppid());
}else{//child
printf("child process, pid = %d, ppid = %d\n", getpid(), getppid());
}//of if
printf("......finish......");
return 0;
}//of main
运行结果如下:
在老师留下的思考题中,多次执行该程序会发现child process后输出的ppid不等于parent process的pid,而等于1。出现这种情况是因为父进程先于子进程终止,子进程变成“孤儿进程”,后面由init进程来接收。但是可能由于重复实验的次数过少,我并没有得到child process的ppid等于1的情况。
问题:不明白为什么是 tempPid == -1 而不是 tempPid <= -1
1.2创建多个进程
int i;
for(i = 0; i < 2; i++){
tempPid = fork();
}
【案例2】
test_fork2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
pid_t tempPid;
int i;
for(i = 0; i < 2; i ++){
if((tempPid = fork()) == 0){
break;
}//of if
}//of for i
if(tempPid == -1){
perror("fork error");
}else if(tempPid > 0){//parent
printf("parent process, pid = %d, ppid = %d\n", getpid(), getppid());
}else{//child
printf("I am child process = %d, pid = %d, ppid = %d\n", i + 1, getpid(), getppid());
}//of if
printf("......finish......");
return 0;
}//of main
运行结果如下:
在老师留下的思考题中,案例2的输出结果有如下问题:
(1)子进程的编号不是递增的是因为在Linux系统中,子进程应由父进程回收,但是当子进程被创建后,它与它的父进程及其它进程共同竞争系统资源,所以父子进程执行的顺序是不确定的,终止的先后顺序也是不确定的。
(2)终端提示符后面仍然有子进程信息打印而命令提示符在最后一行的开头闪烁是因为Shell命令提示符也是一个进程,它需要和新建进程一起竞争CPU。
但是似乎老师提出的第一个问题并未在我的运行结果中出现,不知道是为什么?在学校机房的电脑上运行结果倒是和老师说的相同。
1.3进程的执行顺序:利用sleep函数,暂缓进程执行
【案例3】
test_fork3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
pid_t tempPid;
int i;
for(i = 0; i < 2; i ++){
if((tempPid = fork()) == 0){
break;
}//of if
}//of for i
if(tempPid == -1){
perror("fork error");
}else if(tempPid > 0){//parent
sleep(2);
printf("parent process, pid = %d, ppid = %d\n", getpid(), getppid());
}else{//child
sleep(i);
printf("I am child process = %d, pid = %d, ppid = %d\n", i + 1, getpid(), getppid());
}//of if
printf("......finish......");
return 0;
}//of main
运行结果如下:
总结
1.通过这一次课程,我对相关函数有了初步的了解,想要能够熟练运用,还需要大量的练习;
2.代码都是过了手一遍敲进编译器的,但有一些细节地方尚不清楚原理为何,还需要进一步理解。