【2】进程与等待、守护进程

一、exec 函数族

作用:调用该函数,可以在进程中执行另外的程序
头文件:

 #include <unistd.h>

l ----->list:参数以列表方式呈现
p ------>path:环境变量

1. int execl(const char *path, const char *arg, ...);
2. int execlp(const char *file, const char *arg, ...);
        
3. int execv(const char *path, char *const argv[]);
4. int execvp(const char *file, char *const argv[]);   

返回值:
*成功: 返回当前程序调用结果
*失败:-1
参数:
*path : 执行程序的名称(包含路径)

参数传递:以函数的第5位字母来区分,exec 后面一位:
1.若是子母 l (list):逐个列举参数 ,类型为:const char *arg 命令参数列表必须以NULL结尾
2.若是字母 v (vertor):指针数组传递,类型为 : char *const argv[]

————————————————————————————————————————————

  1. int execl(const char *path, const char *arg, …);
    例:
  • ls -l /etc

使用完整的文件目录来查找对应的可执行文件

相当于执行ps -ef 命令/需要给出ps所在程序的完整路径

execl("/bin/ps","ps","-ef","NULL");

相当于执行 ls -l 命令/需要给出ls -l 所在程序的完整路径

execl ("/bin/ls","ls","-l","/ect",NULL);

注意 : 目录必须以 ”/ “ 开头,否则将其视为文件名 ,excel 的参数, 以NULL结尾

  1. int execlp(const char *file, const char *arg, …)
    参数:
    • file : 要执行文件的名称

2 .使用文件名的方式查找可执行文件

相当于执行 ls -l 命令

execlp("ls", "ls", "-l", "/home/farsight",NULL);//ls---文件名

相当于执行 ps -ef 命令

excelp("ps","ps","-ef","NULL");

与在shell中直接输入命令是一样

  1. int execv(const char *path, char *const argv[]);

参数通过指针数组来传递

char *buf[] = {"ls", "-l", "/etc", NULL};
ret = execv("/bin/ls", buf);
  1. int execle(const char *path, const char *arg,…,char const envp[] );

将环境变量添加到新建的子进程中,env ----->查看当前进程环境变量的命令

将环境变量添加到新建的子进程中

char *envp[] = {"PATH = /tem","USER = sunny",NULL};

if (fork() == 0)
{
	...execle("usr/bin/env","env",NULL,envp);//env --->需要完整路径
}

—————————————————————————————————————————————

二、system —在进程中执行其他命令

头文件:

#include <stdlib.h>
system (const char *command);

参数:
*command : 要执行的命令

/在main函数中执行ls命令/

int main(int argc, char *argv[])
{
	system("ls");
	return 0;
}

三、vfork

特点:

  1. 通过vfork创建的子进程,父子进程共用同一片地址空间
  2. 子进程优先于父进程运行
  3. 子进程调用exec函数族中的函数或者子进程调用exit()函数后,父进程才有可能执行

vfork 的子进程调用execl 函数后(子进程空间被其他进程替换),此时父进程不会再等待子进程结束,而是和子进程抢空间


四、wait() 和waitpid()

1.wait()—父进程等待子进程结束,回收其资源

头文件:

#include <sys/types.h>
#include <sys/wait.h>

原型;

pid_t wait(int *status);

返回值:
*成功:等待子进程的进程号
*失败:-1
参数;

  • status ;保存进程退出的属性

一般是父进程使用wait函数等待回收子进程
特点:

  1. 在父进程等待子进程结束的过程中,父进程会阻塞直到子进程退出或者接受到指定信号为止
  2. wait函数一次只能回收一个子进程,哪个先结束,就先回收哪个
  3. 如果该父进程没有子进程,或者子进程已经结束,则wait 会立即返回-1
WIFEXITED(status) --- 判断子进程是否正常退出  1-正常退出  0-非正常	WEXITSTATUS(status) --- 获取正常退出的返回值
WIFSIGNALED(status)  ---  判断是否因为信号退出
WTERMSIG(status)  --- 返回具体是哪一个信号导致子进程退出
2. waitpid()-----等待接收指定的任意子进程

头文件:

#include <sys/types.h>
#include <sys/wait.h>

原型:

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

参数:
*pid:
-1 : 回收任意子进程
指定pid号 : 接收等待回收指定子进程
*status :保存进程退出的属性
*option :
0:阻塞方式回收
WNONHANG:非阻塞方式,不会等待子进程先结束

例:

waitpid(-1, &stauts, 0);
waitpid(-1, &stauts, WNOHANG);
waitpid(pid, &stauts, 0);
waitpid(pid, &stauts, WNOHANG);
/***调用waitpid,进程阻塞***/
pid_t ret = waitpid (pid,NULL,0);

/***调用wait ,父进程不阻塞***/
pid_t ret = waitpid (pid,NULL,WNOHANG);

五、守护进程

守护进程一般在系统启动时运行,系统关闭时结束------一般用于后台服务器

特点

  1. 始终在后台运行,不会影响前台进程的运行
  2. 独立于任何终端,不能输入,也不能输出
  3. 周期性地执行程序,或者等待某些事件的响应

相关概念:
进程组

  1. 一个或者多个进程的集合,进程组又进程ID唯一标识
  2. 当用户运行一个进程时,就创建了一个进程组,运行进程中创建的所有具有亲缘关系的进程都属于当前进程组
  3. 每个组都又一个组长进程,组长进程的ID号就是进程组的ID号;但是进程组的ID号不会收组长进程的退出的影响

会话

  1. 是一个或者多个进程组的集合,当用户打开一个终端时,就会产生一个会话
  2. 会话和终端相关,打开终端,创建一个会话,关闭终端,会话中所有进程会被强行结束

创建守护进程步骤

1. 创建一个子进程,父进程退出

父进程退出的原因:使子进程变为孤儿进程,被init进程收养,由前台进程变为后台进程

pid_t pid = fork);
if (pid > 0)
{
	exit (0);//父进程退出 
}
2. 创建一个新的会话------setsid()

目的: 让子进程脱离原来的会话,成为新的会话组长
setsid():创建一个新的会话,并担任该会话组的组长进 3个作用:

  1. 让进程摆脱原会话的控制
  2. 让进程摆脱原进程组的控制
  3. 让进程摆脱原控制终端的控制

头文件:

#include <sys/types.h>
#include <unistd.h>

原型:

pid_t setsid (void);

返回值:
*成功:返回进程组ID
*失败: -1

3. 更改工作目录

要么设置为根目录,要么设置为"/tmp"

chdir("/");    

chdir ("/tem");
4. 重设文件权限掩码

由于用fork 函数创建的 子进程继承了父进程的文件权限掩码吗,这给孩子进程使用文件带来了一定的影响。因此把文件权限掩码设置为0 (~&后是 其本身)

umask(0)
5. 关闭打开的文件描述符------getdtabesize()
int i = 0
for(i = 0; i < getdtablesize(); i++)
		{
				close(i);
		}
		while(1)
	{
				任务;			
	}

练习:创建守护进程,周期性地向time.log文件中输入当前时间

 12 #include <stdio.h>
 13 #include <string.h>
 14 #include <stdlib.h>
 15 #include <strings.h>
 16 
 17 #include <sys/types.h>
 18 #include <unistd.h>
 19 #include <time.h>
 20 
 21 
 22 int main()
 23 {
 24         FILE *fp ;
 25 
 26         int i;
 27         time_t t;
 28         time(&t);
 29         struct tm *ltime;
 30         //创建子进程,并退出父进程
 31         pid_t  pid = fork();
 32 
 33         if (pid > 0)
 34                 exit (1);
 35 
 36         //创建一个新的会话
 37 
 38         int ret = setsid();
 39         if (ret < 0)
 40                 exit (2);
 41 
 42         //更改目录
 43         chdir("/tem");
 44 
 45 
 46         //设置文件权限掩码
 47         umask(0);
 48 
 49         /关闭文件描述符
 50         int num = getdtablesize();
 51         for (i = 0; i< num;i++)
 52         {
 53                 close(i);
 54         }
 55 
 56         fp = fopen("time.log","a+");//追加:另起一行
 57         if ( fp == NULL)
 58                 exit (3);
 59         while (1)
 60         {
 61              
 62 
 63                 fprintf(fp,"%s",ctime(&t));
 64                 fflush(fp);
 65                 sleep(1);
 66         }
 67 
 68         return 0;
 69 }

在这里插入图片描述

——————————————————————————————————————————————————————

小点点:

/***main 函数 参数的用法 ***/
int main (int argc,char *argv[]) //命令行参数
{
if (argc < 3)
{
printf(“Uage : %s ”);
execl (-1);// execl (-1) == return -1;
}

}

如输入命令 :./a.out
Usage : ./a.out //提示语句

命令:./a.out can1 can2
…<运行结果>
参数:
argc :命令行参数个数 (3)
argv[]: argv[0]----><命令行的第一个参数>(./a.out) ;argv[1]----><命令行的第二个参数 > (can1);argv[2]---->命令行的第三个参数 (can2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值