Linux并发程序设计-进程讲解(3)


进程 - 第一讲链接
进程 - 第二讲链接

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)//获取结束子进程的信号类型
    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;
}
  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值