Linux进程控制

一、进程的创建、终止、等待

进程创建:(我的上一篇博客关于fork()函数做了比较详细的介绍,这里就不再罗嗦了;)

#include<stdio.h>
#include<unistd.h>
int main()
{
	int ret=fork();
	if(ret>0)
	{
		printf("father: %d\n",getpid());
	}
	else if(ret==0)
	{
		printf("child: %d\n",getpid());
	}
	else
	{
		printf("perror fork()\n");
	}
	return 0;
}


进程的终止:
常见的进程终止方式有三种:
(1)代码执行完毕,结果正确
(2)代码执行完毕,结果不正确
(3)代码未执行完毕,异常终止
代码执行完的情况:
1.main函数返回,返回值叫做进程的退出码,通过退出码可以判断运行结果是否正确(也可以刷新缓冲区);退出码为0表示结果正确,退出码非0表示结果不正确(指令:ecoh $可以查看上个命令对应程序的退出码)
2.exit(库函数)进程退出;本质上是调用_exit
exit关闭流并刷新缓冲区;exit还多调用了结束函数(结束函数atexit(函数指针):main函数结束执行调用函数);
3._exit进程退出(系统调用);_exit不会刷新缓冲区。

#include<stdio.h>
#include<unistd.h>
int main()
{
	printf("hello word");
	exit(0);
	//_exit(0);

在这里插入图片描述
(图片第二行是使用exit(0)运行的结果;第四行是使用_exit(0)运行的结果)
异常退出:
ctrl+c:信号终止
进程等待:(父进程对子进程进行进程等待,等待是为了读取子进程的运行结果)
wait方法:

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
	int ret=fork();
	if(ret>0)
	{
		printf("father :%d\n",getpid());
		printf("father wait child end\n");
		pid_t pid=wait(&ret);
		printf("wait %d\n",pid);
		printf("father end\n");
	}
	else if(ret==0)
	{
		sleep(5);
		printf("child: %d\n",getpid());
		printf("child end\n");
	}
	else
	{
		perror("fork");
	}
	return 0;
	

在这里插入图片描述
成功返回等待进程的pid,失败返回-1
1.参数是输出型参数(表示退出码+正常/异常退出)
2.返回值是子进程的pid
3.阻塞式的等待,一直到子进程结束才返回wait的
注意事项:wait的调用次数必须和子进程的个数一致wait的调用次数比较少,会导致僵尸进程wait的调用次数比较多,多出来的wait就会调用出错如果有多个子进程,任何一个子进程结束都会触发wait的返回
waitpid()方法:

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
int main()
{
	 int ret=fork();
	 if(ret>0)
	 {
		  printf("father :%d\n",getpid());
		  printf("father wait child end\n");
		  pid_t pid=waitpid(ret,NULL,0);//父进程等待指定的子进程
		 // pid_t pid=waitpid(-1,NULL,0);//父进程等待任何一个子进程
	        // pid_t pid=waitpid(-1,NULL,WNOHANG);//非阻塞式等待
		  printf("wait %d\n",pid);
		  printf("father end\n");
	 }
	 else if(ret==0)
	 {
  		sleep(5);
 		 printf("child: %d\n",getpid());
		 printf("child end\n");
	 }
	 else
	 {
 		 perror("fork");
	 }
	 return 0;
 }

在这里插入图片描述
pid_t pid=waitpid(ret,NULL,0);运行的结果
在这里插入图片描述
pid_t pid=waitpid(-1,NULL,0);运行的结果
在这里插入图片描述
pid_t pid =waitpid(-1,NULL,WNOHANG);运行的结果
waitpid:指定某个子进程进行等待
waitpi能够等待某个指定子进程的退出行为和wait非常相似(返回值规则,status参数)waitpid(-1,NULL,0)就和wait(NULL是等价的
非阻塞轮循式的wait:
好处是:能够更接灵活的控制代码,充分利用等待时间去做其他的事情
坏处是:代码更加复杂

封装fork/wait等操作, 编写函数 process_create(pid_t* pid, void* func, void* arg), func回调函数就是子进程执行的入口函数, arg是传递给func回调函数的参数

  #include <stdio.h>                                                                                                                              
  #include<unistd.h>
  #include<sys/wait.h>
  void process_create(pid_t* pid,void* func,void*argv)
  {   
     {   
         if((*pid = fork()) == -1){
             perror("fork");
             return ;
             
         }   
         if(*pid == 0){ 
             ((int (*)())func) (((char**)argv)[0],(char**)argv);
            perror("func");
        }
         else {  
                int state;
                 while( wait(&state) != *pid  );
         }
     }
 }
 int main()
 {
     pid_t pid;
     char* argv[]={"ls","-l",NULL};
     process_create(&pid,execvp,argv);
     return 0;
 }

运行结果:
在这里插入图片描述

popen/system, 这两个函数和fork的区别

popen:
是标准c提供的一个管道创建函数,其内部操作主要是创建一个管道,调用fork创建子进程,关闭不需用的文件描述符,调用exec函数族执行popen的第一个参数。然后等到关闭。

FILE popen( const char command, const char* mode )
参数说明:
command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令。
mode: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到command 的标准输入。
返回值:
如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断。
注意:
popen() 函数用创建管道的方式启动一个 进程, 并调用 shell. 因为管道是被定义成单向的, 所以 type 参数只能定义成只读或者只写, 不能是两者同时, 结果流也相应的是只读或者只写。
popen() 函数的返回值是一个普通的标准I/O流, 它只能用 pclose() 函数来关闭, 而不是 fclose() 函数. 向这个流的写入被转化为对 command 命令的标准输入; 而 command 命令的标准输出则是和调用 popen()函数的进程相同,除非这个被command命令自己改变. 相反的, 读取一个 “被popen了的” 流, 就相当于读取 command 命令的标准输出, 而 command 的标准输入则是和调用 popen函数的进程相同。
system:
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
int system(const char * string);
返回值:
若=-1:出现错误
若=0:调用成功但未创建子进程
若 >1:成功,子进程的pid
如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值。
如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。
system执行过程:
1.fork创建一个子进程
2.在子进程中调用exec函数去执行command
3.在父进程中调用wait去等待子进程结束

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值