进程相关(创建-回收-exec-守护进程)

1.进程的创建与回收

1.1创建

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
	pid_t pid = fork();

	if( pid < 0 ){
		perror( "fork" );
		return 0;
	}else if( 0 == pid){
		printf( "这是子进程!\n" );
	}else{
		printf( "这是父进程!\n" );
	}
}

1.2 回收子进程

wait( &status );

阻塞回收,WEXITSTATUS(status)

成功时返回回收的子进程的进程号;失败时返回EOF

若子进程没有结束,父进程一直阻塞

若有多个子进程,哪个先结束就先回收

status 指定保存子进程返回值和结束方式的地址

status为NULL表示直接释放子进程PCB,不接收返回值

#include  <unistd.h>
  pid_t waitpid(pid_t pid, int *status, int option);

参数:

pid
pid>0时,等待该pid的子进程结束,不管其它子进程。

pid=-1时,等待任意子进程退出,此时waitpid和wait的作用相同。

pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。

pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

options

options提供了一些额外的选项来控制waitpid,目前在Linux中只支持

WNOHANGWUNTRACED两个选项,

这是两个常数,可以用"|"运算符把它们连接起来使用

WNOHANG :若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞,立即返回0

WUNTRACED: 返回终止子进程信息和因信号停止的子进程信息

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
	int status;
	pid_t pid = fork();

	if( pid < 0 ){
		perror( "fork" );
		return 0;
	}else if( 0 == pid){
		printf( "这是子进程!\n" );
		exit( 0 );
	}else{
		printf( "这是父进程!\n" );
		//wait( &status );阻塞回收
		int rpid = waitpid( -1, &status, WNOHANG );
		printf( "子进程返回状态值status = %x \n", WEXITSTATUS(status) );
	}
	
	return 0;
}

2.exec函数族与守护进程

2.1 exec函数族

背景:
fork创建子进程之后,

子进程和父进程执行相同的代码,

但是在实际开发中,我们希望父子进程执行不同的代码。

作用:执行指定的程序

#include  <unistd.h>
  int execl(const char *path, const char *arg,);
  int execlp(const char *file, const char *arg,);

成功时执行指定的程序;失败时返回EOF

path 执行的程序名称,包含路径

arg… 传递给执行的程序的参数列表

file 执行的程序的名称,在PATH中查找

两个函数区别:
execlp不需要写文件名全路径,在PATH查找

最后一个参数必须用空指针(NULL)作结束

进程当前内容被指定的程序替换,但进程号不变

第0个参数必须要写,虽然它没有使用

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, const char *argv[])
{
	pid_t child1, child2, child;
	//创建两个子进程
	child1 = fork();
	child2 = fork();

	//子进程1的出错处理
	if(-1 == child1){
		perror("1 fork error");
		exit(1);
	}else if(0 == child1){                    //子进程1中执行其他程序
		printf("调用execlp(),执行ls -l\n");
		if(execlp("ls", "ls", "-l", NULL) < 0){
			printf("child1 execlp error\n");
		}
	}

	//子进程2的出错处理
	if(-1 == child2){
		perror("child2 fork error");
		exit(1);
	}else if(0 == child2){                //子进程2中执行其他程序
		printf("暂停5秒\n");
		sleep(5);
		exit(0);
	}else{
		printf("在父进程中等待两个子进程的退出\n");
		child = waitpid(child1, NULL, 0);//非阻塞等待
		if(child == child1){             //进程1退出
			printf("Get child1 exit code\n");		
		}else{
			printf("error!\n");
		}

		do
		{
			child = waitpid ( child2, NULL, WNOHANG ) ;//非阻塞式等待,需要循环等待
			if ( child == 0 ){
				printf("子进程2还未结束\n");
				sleep(1);
			}
		}while ( 0 == child);

		if ( child == child2 ){
			printf("Get child2 exit code\n");
		}else{
			printf("Error!\n");
		}
	}
		exit ( 0 ) ;
}

2.2 守护进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main ()
{
	FILE* fp;
	time_t t;

	pid_t pid = fork();
	if( pid < 0 ){
		perror("fork");
		return 0;
	}
	//1.创建子进程,父进程退出
	else if( pid > 0 ){
		exit( 0 );
	}
	printf("\nbefore setsid:sid=%d pid=%d gpid=%d\n", 
			getsid( getpid() ), getpid(), getpgid( getpid() ) );
	//2.设置sid
	if( setsid() < 0 ){
		perror("setsid");
		exit( 0 );
	}
	printf("after setsid:sid=%d pid=%d gpid=%d\n", 
			getsid( getpid() ), getpid(), getpgid( getpid() ) );
	//3.更改工作目录
	chdir("/tmp");

	//4.设置文件掩码
	if( umask(0) < 0 ){
		perror("umask");
		exit(0);
	}
	//5.关闭文件描述符
	close(0);
	close(1);
	close(2);

//打开文件time.log
	if( (fp = fopen("time.log" , "a")) == NULL){
		perror("fopen");
		exit(-1);
	}

	while(1){
		time( &t );
		fprintf( fp, "%s", ctime(&t) );
		fflush( fp );
		sleep(1);
	}
	return 0;
}
time() 函数:
		获取系统当前的时间,返回一个以秒为单位的整数值。
ctime() 函数:
		将time_t 类型的时间值转换为一个字符串,
		函数返回的字符串是一个指向静态分配缓冲区的指针。
fprintf() 函数:
		将格式化的数据写入文件或流中
fflush() 函数:
		将缓冲区中的数据写入文件或流中。	
sleep() 函数:
		使进程挂起指定的时间,以秒为单位。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值