进程 - 第三讲
进程 - 第一讲链接
进程 - 第二讲链接
8进程exec函数族
- 进程调用exec函数族执行某个程序(一般创建进程的过程,在shell下执行程序,创建子进程);
- 进程当前内容被指定的程序替换;代码段、数据段、堆栈等;
- 实现让父子进程执行不同程序
(1)父进程创建子进程
(2)子进程调用exec函数族
(1)execl/execlp
#include<unistd.h>
int execl(const char *path,const char *arg,''');
int execlp(const char *file ,const char *arg,''');
- 成功执行指定的程序,包含路径
- arg传递给执行程序的参数列表
- file执行程序名称在PATH中找
实例:执行ls命令显示/etc目录下所有文件的详细信息
if(execl("/bin/ls","ls","-a","-l","/etc",NULL) < 0){
perror("execl");
}
if(execl("ls","-a","-l","/etc",NULL) < 0){
perror("execlp");
}
(2)execv/execvp
#include <unistd.h>
int execv(const char *path ,char *const argv[]);
int execvp(const char *file, char *const argv[]);
(3)system
#include <stdlib.h>
int system(const char *command);
- 成功返回command的值,失败返回EOF;
- 当前进程等待command执行完之后才执行
9进程回收
- 子进程有父进程回收
- 孤儿进程由init进程回收
(1)wait
#include<unistd.h>
pid_t wait(int *status);
- 成功返回子进程的进程号(>0),失败返回EOF;
- 子进程没有结束,父进程处于阻塞态;
- 若有多个进程,那个线回收呢?
哪个子进程先结束,wait就先回收那个; - status 保存子进程返回值和结束方式地址。
实例:
int status;
pid_t pid;
if((pid = fork()) < 0){
perror("fork");
exit(-1);
}
else if(pid == 0){
sleep(1);
exit(2);
}
else{
wait(&status);
printf("%x\n",status);
}
(2)waitpid
#include <unistd.h>
pid_t waitpid (pid_t pid, int *status,int option);
- 成功返回回收的子进程的pid或0,失败返回EOF;
- pid指定回收哪一个子进程
- option 回收当时 0(父进程阻塞)|| WHOHANG(用于非阻塞,必须掰断返回值,返回0 失败,返回子进程号表示成功)。
实例`
waitpid(pid, &status,0);//以阻塞方式回收进程
waitpid(pid, &status,WHOHANG);//以非阻塞方式回收进程
waitpid(-1, &status,0);//等同于wait
waitpid(-1, &status,WHOHANG);
进程返回值和结束方式
- 正常结束 子进程通过exit/_exit/return 返回某个值,值在0-255;
- 非正常结束调用wait(&status)回收
访问status的各个位
- WIFEXITED(status)//判断子进程是否正常结束;
- WEXITSTATUS(status)//获取子进程的返回值;
- WIFSIGNLED(status)//判断子进程是否被信号结束
- WTERMSIG(status)//获取结束子进程的信号类型
10守护进程
- 始终在后台运行;
- 独立于任何终端;
- 周期性执行某种任务或等待处理特定事件。
会话,控制终端
- Linux以会话,进程组的方式管理进程;
- 会话是一个或多个进程组的集合;
- 通常用户打开一个终端时,系统就会创建一个会话,所有在终端上运行的进程都属于这个会话。
11守护进程的创建
(1)创建子进程,父进程退出
运行程序后,进程是交互进程,当前进程依附于打开的终端
if(fork() > 0){
exit(-1);
}
- 子进程变成孤儿进程,被init进程收养;
- 子进程在后台运行,依然依附于终端
(2)子进程创建新会话
if(setsid() < 0){
exit(-1);
}
- 子进程成为新会话的组长;
- 子进程脱离原先的终端。
(3)修改进程啊当前目录
chdir(“/”);//根目录可读不可写
chdir("/tmp"); //可读可写可执行
- 守护进程一直在后台运行,其工作目录不能被卸载;
- 重新设定当前目录cmd。
(4)重设文件权限掩码
if(umask(0) < 0){//不能屏蔽任何权限位
exit(-1);
}
(5)关闭打开的文件描述符
int i;
for(i = 0;i < getdtablesize(); i++){//getdtablesize()表示当前进程能打开的最大个数
close(1);
}
- 关闭所有父进程继承的打开文件;
- 已脱离终端,stdin/stdout/stderr 无法使用
实例:创建守护进程,每个1s将系统时间写入time.log
int main(){
pid_t pid;
FILE *fp;
time_t t;
int i;
if( pid == fork()) < 0){
perror("fork");
exit(-1);
}//创建进程
else if(pid > 0){
exit(-1);
}//父进程退出
setsid(1);//创建新会话
umask(0);//重设掩码
chdir("/tmp");//修改当前目录
for( i = 0; i <getstablesize(); i++){
close(i);
}//关闭打开的描述符
if(( fp = fopen(time.log,"a")) == NULL){
perror("fopen");
exit(-1);
}//j将时间追加到末尾
while(1){
time(&t);
fprintf(fp, "%s", ctime(&t));//将t改为本地时间
fflush(fp);
sleep(1)
}
return 0;
}