5.进程:概念和进程的API(vfork-getpid-wait-exec-system-popen)

目录

    1.概念

    2.类型

    3.进程标识符,类型:pid_t 。  (=pid) ;

    4.API

      4.1 进程创建 :vfork()

      4.2 查看进程

                4.3.收回子进程 : wait

                4.4.收回子进程 : waitpid

                4.5.退出

                4.6.进程替换和中断

         (1) 进程  “替换”    exec族      

                          4.7 system

                           4.8 popen


    1.概念

        从用户角度:进程就是一个正在运行中的程序。

        查看进程:ps -aut|grep  +进程蕴含信息

        fork创建的进程,代码由父子进程共享,写时复制,内核将这些区域定义为只读,需要修改时再复制

    2.类型

        僵尸进程

            子进程退出状态不被收集,变成僵死进程   Z+    S+表示正在运行

        孤儿进程

            父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程

            Linux避免系统存在过多孤儿进程,init进程(返回1)收留孤儿进程,变成孤儿进程的父进程

    3.进程标识符,类型:pid_t 。  (=pid) ;

        每个进程都有一个非负整数表示的唯一ID,叫做pid,类似身份证

        Pid=0:  称为交换进程(swapper)作用:进程调度

        Pid=1:init进程 ,作用 :系统初始化

    4.API

         4.1 进程创建 :vfork()

            它从已存在的进程中创建一个新进程。新进程为子进程,而原进程为父进程。

            fork运行后,父子进程共享fork往后的代码,共享数据段变量、堆栈。当父进程或者子进程,需要改变变量时,内核复制一个变量给予修改,原变量不变。

            先后:没有先后,可同时运行。先后取决于进程调度

            返回

返回值非负数(子进程ID)代表当前进程为父进程
返回值为0(通过getppid调取父进程ID)代表当前进程是子进程
    创建失败返回-1

            vfork 直接使用父进程存储空间,不拷贝。

            vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

         4.2 查看进程

            getpid()

                查看当前程序的进程ID

            getppid()

                查看当前程序的父进程ID

        4.3.收回子进程 : wait

            pit_t  wait(int *status)

            函数功能

                ●如果其所有子进程都还在运行,则阻塞。s+

                .如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。

                ●如果它没有任何子进程,则立即出错返回-1

                如果先终止父进程,子进程将继续正常进行,只是它将由init进程(PID 1)继承,当子进程终止时,init进程捕获这个状态

            返回

                wait会返回被收集的子进程的进程ID,存在status中,但是要用WEXITSTATUS解析才能正常显示。exit(3)_ 正常退出:*status=3  异常退出 *status!=3,注意要用WEXITSTATUS解析才能正常显示。是否正常退出用WIFEXITED(status)!=0检测,异常=0

                -1:没有子程序,wait在fork之前

                空:不关心退出状态

            status相关操作

WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。
WEXITSTATUS(status) 当WIFEXITED返回非零值时,可解析子进程的返回值,传送给exit.- exit或 Exit参数的低8位
WIFSIGNALED (status )若为异常共止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG (starus), 取使子进程线止的信号编号。另外,有些实现(非Single UNIX Specifcation) 定义宏WCOREDUMP (stanes), 若已产生终止进程的core文件,则它返回真
WIFSTOPPED (stomus)若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(staus),取使子进程暂停的信号编号
WIFCONTINUED (status)若在作业控制暂停后已经继续的子进程返回了状态,则为真。(POSIX.I的XSI扩展:仅用于waitpid.)

        4.4.收回子进程 : waitpid

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

            函数功能

                ●如果其所有子进程都还在运行,则阻塞。可以不阻塞

                .如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。

                ●如果它没有任何子进程,则立即出错返回

                如果先终止父进程,子进程将继续正常进行,只是它将由init进程(PID 1)继承,当子进程终止时,init进程捕获这个状态

            返回

                wait会返回被收集的子进程的进程ID

                -1:没有子程序,wait在fork之前

                空:不关心退出状态

            pid

pid>0时只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
  pid=-1等待任一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值

      

            options

WCONTINUED若实现支持作业控制。那么由pid指定的任一子进程在暂停后已经继续, 但其状态尚未报告,则返回其状态(POSIX.1的XSI扩展)
WNOHANG若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0
WUNTRACED若某实现支持作业控制,而由pid指定的任-“ 子进程已处于暂停状态,井且其状态自暂停以来还未报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应于一个暂停子进程

            status相关操作

                        

WIFEXITED(status)  这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。
WEXITSTATUS(status) 当WIFEXITED返回非零值时,可解析子进程的返回值,传送给exit.- exit或 Exit参数的低8位
WIFSIGNALED (status )      若为异常共止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG (starus), 取使子进程线止的信号编号。另外,有些实现(非Single UNIX Specifcation) 定义宏WCOREDUMP (stanes), 若已产生终止进程的core文件,则它返回真
WIFSTOPPED (stomus)     若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(staus),取使子进程暂停的信号编号
WIFCONTINUED (status)    若在作业控制暂停后已经继续的子进程返回了状态,则为真。(POSIX.I的XSI扩展:仅用于waitpid.)

            注意:调用WNOHANG不阻塞时,不接受子程序的返回,变僵死程序

    4.5.退出

        正常退出

            Main函数调用return

            进程调用exit(),标准c库       0   1  2   ,会冲刷缓冲区

            进程调用_exit()或者_Exit(),属于系统调用  直接退出

            进程最后一个线程返回

            最后一个线程调用pthread_exit

       异常退出

            调用abort,等于放弃当前进程

            当进程收到某些信号时,如ctrl+C,等于强制停止

            最后一个线程对取消(cancellation)请求做出响应

        概念

            任何进程如何终止的,最后内核都会执行同一段代码,这段代码会为相应进程关闭所有打开的描述符,释放相应的存储器

            对上述任意-种终止情形、 我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit、_ exit和_ Exit), 实现这一点的方法是,将其退出状态(exit status),作为参数传送给函数。

            在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。 在任意一 种情况下,该终止进程的父进程都能用wait或waitpid函数(在下一节说明)取得其终止状态。

    exec为替换进程,不执行下面内容,而   system,可以执行以下内容

    4.6.进程替换和中断

         (1) 进程  “替换”    exec族      linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)_牛仔的blog-CSDN博客_execleexec族函数函数的作用:我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。exec族函数定义:  可以通过这个网站查询:linux函数查询 功能:   在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执https://blog.csdn.net/u014530704/article/details/73848573

                功能:

                    我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变

                    在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

                API

execlint execl(const char *path, const char *arg, ...);通过路径,找到可执行文件(第一个参数),然后加上后面传入的参数 运行程序   ls  ,-l ,NULL
execlpint execlp(const char *file, const char *arg, ...);不同:file可以为路径(包含/),也可以为可执行文件名字(第一参数),为名字时通过环境变量PATH,找到文件执行
execleint execle(const char *path, const char *arg,..., char * const envp[]);
execvint execv(const char *path, char *const argv[]);应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
execvpint execvp(const char *file, char *const argv[]);应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
execvpeint execvpe(const char *file, char *const argv[],char *const envp[]);

                参数

                    path:可执行文件的路径名字 ,直接加入路径,不需要加  .  。‘ . ’代表缺省的路径,这里无缺省

                    arg:可执行程序所带的参数,第一个参数为可执行文件名字,第二个及以后的参数为运行这个程序时跟在命令行的参数。没有带路径且arg必须以NULL结束

                        例: execl("/bin/rm","rm","-r",NULL)   替换为了 rm 文件 = 命令行的  "rm -r"

                        例:char *argv[] = {"ps","-l",NULL};        execvp("ps",argv)

                    file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

                        不同:file可以为路径,也可以为可执行文件名字(第一参数),为名字时通过环境变量PATH,找到文件执行

                返回

                    exec函数族的函数执行成功-----不会返回

                    调用失败时,会设置errno并返回  “-1”  ,然后从原程序的调用点接着往下执行。

                记忆

                    l : 使用参数列表

                        execl、execlp、execle

                    p:使用文件名,并从PATH环境进行寻找可执行文件

                        execlp、execvp、execvpe

                    v不带l:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。

                        execv、execvp、execve

                    e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量

                        execle、execvpe

        进程中,加入运行其他进程 

              4.7 system

linux system函数详解 - 南哥的天下 - 博客园system()函数功能强大,我对linux中的实现比较了解,具体分析这个,windows中的类似就不详解了。好了,先看linux版system函数的源码:代码:#include#include#inhttps://www.cnblogs.com/leijiangtao/p/4051387.html

                 int system(const char * string);   ” a.out“

                可直接写入路径或者命令参数

                返回

                    成功,则返回进程的状态值;

                    当sh不能执行时,返回127;

                    失败返回-1;

   4.8 popen

                FILE * popen(const char *command , const char *type );

                自己创建进程,运行命令(command),将运行结果或者是运行信息,通过创建的管道发送到文件中,返回这个文件的描述符,再pclose关闭管道,可以用fread()读取结果

                type

                    type的可选值为“w”或“r”,代表可读与可写。代表popen返回的文件的属性。

                    w   可读,标准输入

                    r    可写,标准输出

                返回 ;文件描述符

            自己创建进程,运行命令

注意:system 可以返回代码段,运行下面的代码,popen可以返回输出结果

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

int main(){
	pid_t pid;
	int cen=0;
	int stuta=0;
	
	pid=fork();
	
	if(pid>0){
		wait(&stuta);
		printf("stuta==%d\n",WEXITSTATUS(stuta));
		while(1){
			printf("This is father ID:%d\n",getpid());
			sleep(1);
		}
	}else{
		execl("/bin/ls","ls",NULL,NULL);// open格式 ./aaa   ‘ . ‘可以看作缺省路径
		execl("./bin/ls","ls","NULL",NULL);// 此处没有缺省。不需要
		while(1){
			printf("This is son  ID:%d  cen=%d\n",getpid(),cen);
			sleep(1);
			cen++;
			if(cen==5){

				a=system("ls");
				if(a==-1)
					printf("filed\n"); 
				execl("/bin/ls","ls",NULL,NULL);	
				exit(2);

			}
		}

	}
	return 0;
}

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

int main(){
	char p[1024]={0};
	FILE *fp=NULL;
	fp=popen("ls","r");
	int nread=fread(p,1,1024,fp);
	printf("The news is %d byte and  %s\n",nread,p);
	pclose(fp);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值