进程

程序与进程

  • 程序:解决某个问题或得到某个结果的可以由计算机等具有信息处理能力的装置执行的代码化指令序列,如:exe、a.out、gcc编译后的执行文件。是静态的文件。
  • 进程:程序跑起来后系统会生成一个进程,每个进程有唯一的进程标识符->pid。

查看进程

  • ps指令结合grep过滤
  • top指令

 进程标识符

 每个进程有唯一的进程标识符->pid。pid=0时为交换进程,用于进程调度。pid=1时为初始化进程,用于系统初始化。

获取pid:getpid()-->获取自身pid。getppid()-->获取父进程的pid。

程序存储空间分配

 低地址至高地址:代码区(正文段),局部变量区(初始化段),全局变量区(未初始化段),堆空间,栈空间。

创建进程

fork函数 

手册页

命令:man 2 fork

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

       pid_t fork(void);

DESCRIPTION
       fork()  creates  a  new process by duplicating the calling process.  The new process is
       referred to as the child process.  The calling process is referred  to  as  the  parent
       process.
RETURN VALUE
       On  success,  the PID of the child process is returned in the parent, and 0 is returned
       in the child.  On failure, -1 is returned in the parent, no child process  is  created,
       and errno is set appropriately.

功能

创建子进程,子进程会复制父进程的变量数据和堆、栈空间,只共享正文段,并再次执行一次代码。父子进程运行次序不固定。

返回值

父进程获得子进程的pid,子进程获得0,失败为-1。

实例

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

void forkProcess(int* point)
{
        int inPoint = 20;
        printf("before point: %d\n", *point);
        printf("before inPoint:%d\n", inPoint);

        pid_t forkRet = fork();
        if(forkRet>0){
                *point = 10;
                printf("fater process, this pid is: %d\n", getppid());
        }else{
                inPoint = 100;
                printf("child process, this pid is: %d\n", getpid());
        }
        printf("after point: %d\n", *point);
        printf("after inPoint: %d\n", inPoint);
}

void printTest()
{
        printf("end begin return \n");
}


int main()
{
        int point = 0;
        forkProcess(&point);
        printTest();
        return 0;
}

运行结果

scorhl@scorhl-virtual-machine:~/c/linux/process$ ./a.out 
before point: 0
before inPoint:20
fater process, this pid is: 2269
after point: 10
after inPoint: 20
end begin return 
child process, this pid is: 2779
after point: 0
after inPoint: 100
end begin return 

 vfork函数 

手册页

命令:man 2 vfork

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

       pid_t vfork(void);

DESCRIPTION

       Linux description
               vfork(), just like fork(2), creates a  child  process  of  the  calling
               process.  For details and return value and errors, see fork(2).

               vfork()  is  a special case of clone(2).  It is used to create new pro‐
               cesses without copying the page tables of the parent process.   It  may
               be  useful  in performance-sensitive applications where a child is cre‐
               ated which then immediately issues an execve(2).

功能

创建子进程,子进程使用父进程存储空间,不拷贝。保证子进程先执行,在子进程调用退出后才执行父进程

返回值

父进程获得子进程的pid,子进程获得0,失败为-1。

实例

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

void forkProcess(int* point)
{
	int inPoint = 20;
	printf("before inPoint:%d\n", inPoint);
	
	pid_t forkRet = vfork();

	if(forkRet>0){
	        printf("fater process\n");
	        printf("after inPoint: %d\n", inPoint);

	}else{
		int i = 0;
		while(i++ < 3){
                	printf("child process\n");
		        printf("after inPoint: %d\n", inPoint++);
		}
		exit(1);
	}
}

void printTest()
{
	printf("end begin return \n");
}


int main()
{
	int point = 0;
	forkProcess(&point);
	printTest();
	return 0;
}

运行结果

scorhl@scorhl-virtual-machine:~/c/linux/process$ ./a.out 
before inPoint:20
child process
after inPoint: 20
child process
after inPoint: 21
child process
after inPoint: 22
fater process
after inPoint: 23
end begin return 

退出/等待进程

正常退出

  • main函数调用return
  • 进程调用标准C库中的exit()函数
  • 进程调用系统函数_exit()或_Exit()函数
  • 最后一个进程返回
  • 最后一个进程调用pthread_exit()

异常退出

  • 调用abort
  • 当进程收到退出信号,如ctrl+c
  • 最后一个线程对取消(cancellation)请求做出响应

exit()

作用:返回状态字给父进程,父进程以wait()系列接收状态字。

NAME
       exit - cause normal process termination

SYNOPSIS
       #include <stdlib.h>

       void exit(int status);

DESCRIPTION
       The  exit()  function  causes  normal process termination and the least
       significant byte of status (i.e., status & 0xFF)  is  returned  to  the
       parent (see wait(2)).

RETURN VALUE
       The exit() function does not return.
 

 实例

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


int main()
{
        int i = 0;
        pid_t c_id = fork();
        if(c_id>0){
                while(1){
                        printf("father, pid:%d\n", getpid());
                        sleep(1);
                }
        }
        else if(c_id==0){
                while(i++<5){
                        printf("child, pid; %d, i:%d \n", getpid(), i);
                        sleep(1);
                }
                exit(0);
        }
        return 0;
} 

运行结果

wait()

作用:等待进程改变状态。子进程的退出状态不被收集会编程僵尸进程。父进程未收到子进程的退出信号会阻塞。

NAME
       wait, waitpid, waitid - wait for process to change state

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

       pid_t wait(int *wstatus);

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

       int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

DESCRIPTION
       All of these system calls are used to wait for state changes in a child
       of the calling process, and obtain information about  the  child  whose
       state  has changed.  A state change is considered to be: the child ter‐
       minated; the child was stopped by a signal; or the child was resumed by
       a  signal.  In the case of a terminated child, performing a wait allows
       the system to release the resources associated with  the  child;  if  a
       wait  is not performed, then the terminated child remains in a "zombie"
       state (see NOTES below).

       If a child has already changed state, then these calls  return  immedi‐
       ately.   Otherwise,  they block until either a child changes state or a
       signal handler interrupts the call (assuming that system calls are  not
       automatically restarted using the SA_RESTART flag of sigaction(2)).  In
       the remainder of this page, a child whose state has changed  and  which
       has  not  yet  been  waited upon by one of these system calls is termed
       waitable.

RETURN VALUE
       wait():  on success, returns the process ID of the terminated child; on
       error, -1 is returned.

       waitpid(): on success, returns the process ID of the child whose  state
       has changed; if WNOHANG was specified and one or more child(ren) speci‐
       fied by pid exist, but have not yet changed state, then 0 is  returned.
       On error, -1 is returned.

       waitid():  returns  0  on  success  or  if WNOHANG was specified and no
       child(ren) specified by id has yet changed state; on error, -1  is  re‐
       turned.

       Each  of  these calls sets errno to an appropriate value in the case of
       an error.

 实例

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


int main()
{
        int i = 0;
        pid_t c_id = fork();
        if(c_id>0){
                int *status;
                pid_t re_status = wait(status);
                printf("re_status: %d\n", re_status);
                while(1){
                        printf("father, pid:%d\n", getpid());
                        sleep(1);
                }
        }
        else if(c_id==0){
                while(i++<5){
                        printf("child, pid; %d, i:%d \n", getpid(), i);
                        sleep(1);
                }
                exit(0);
        }
        return 0;
}

运行结果

waitpid()

参数:

  • pid_t pid:
    • pid==-1 :任一子进程,与wait等效
    • pid==0  :进程组中的任一子进程
    • pid>0    :进程ID等于pid的子进程
    • pid<-1   :组ID等于pid绝对值的任一子进程
  • int *wstatus
    • WIFEXITED        :正常终止的返回状态,使用WEXITSTATUS获取状态值。
    • WIFSIGNALED   :异常终止的返回状态,使用WTERMSIG获取信号编号。
    • WIFSTOPPED    :暂停的返回状态,使用WSTOPSIG获取信号编号。
    • WIFCONTINUED:暂停后又继续的返回状态。
  • int options
    • WCONTINUED:暂停后又继续未上报。
    • WNOHANG     :不阻塞父进程,返回值为0。
    • WUNTRACED :暂停未上报。

实例

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


int main()
{
        int i = 0;
        pid_t c_id = fork();
        if(c_id>0){
                int *status;
                pid_t re_status = waitpid(-1, status, WNOHANG);
                printf("re_status: %d\n", re_status);
                while(1){
                        printf("father, pid:%d\n", getpid());
                        sleep(1);
                }
        }
        else if(c_id==0){
                while(i++<5){
                        printf("child, pid; %d, i:%d \n", getpid(), i);
                        sleep(1);
                }
                exit(0);
        }
        return 0;
}

运行结果

 注意:子进程还是会变成僵尸进程。

进程调用 

exec族函数

功能:在进程中执行一个可执行文件。

 NAME
       execl, execlp, execle, execv, execvp, execvpe - execute a file

SYNOPSIS
       #include <unistd.h>

       extern char **environ;

       int execl(const char *pathname, const char *arg,  /* (char  *) NULL */);
       int execlp(const char *file, const char *arg,  /* (char  *) NULL */);
       int execle(const char *pathname, const char *arg,  /* (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[], char *const envp[]);

DESCRIPTION
       The  exec() family of functions replaces the current process image with
       a new process image.  The functions described in this manual  page  are
       layered  on  top  of execve(2).  (See the manual page for execve(2) for
       further details about the replacement of the current process image.)

       The initial argument for these functions is the name of a file that  is
       to be executed.

RETURN VALUE
       The  exec() functions return only if an error has occurred.  The return
       value is -1, and errno is set to indicate the error.

 源精彩博文:linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)-CSDN博客

参数:
path:可执行文件的路径名字。
arg:命令名,相当于ls -a中的ls。
file:指定的路径名,默认按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

l - execl(), execlp(), execle()

        要求将新程序的每个命令行参数都说明为 一个单独的参数。这种参数表以空指针结尾。

v - execv(), execvp(), execvpe()

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

e - execle(), execvpe()
       可以传递一个指向环境字符串指针数组的指针。 

p - execlp(), execvp(), execvpe()
       如果参数file中包含路径名,根据路劲查找,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

实例

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


int main()
{
        int input=0; 
        pid_t c_id = fork();
        if(c_id>0){
        }
        else if(c_id==0){
                //相当于在./change目录下执行 ./change 1
                execl("./chang","change","1",NULL);  
                //执行成功后,后面的代码不会运行,会跳到父进程
        }
        return 0;
}

 system函数

简易版的execl函数。执行 dos(windows系统) 或 shell(Linux/Unix系统) 命令。

函数内部调用:execl("/bin/sh", "sh", "-c", command, (char *) NULL);

参数:command  需要执行的命令。

NAME
       system - execute a shell command

SYNOPSIS
       #include <stdlib.h>

       int system(const char *command);

DESCRIPTION
       The  system()  library function uses fork(2) to create a child process that executes
       the shell command specified in command using execl(3) as follows:

           execl("/bin/sh", "sh", "-c", command, (char *) NULL);

       system() returns after the command has been completed.

RETURN VALUE
       The return value of system() is one of the following:

       *  If  command  is  NULL,  then  a nonzero value if a shell is available, or 0 if no
          shell is available.

       *  If a child process could not be created, or its status could  not  be  retrieved,
          the return value is -1 and errno is set to indicate the error.

       *  If  a  shell could not be executed in the child process, then the return value is
          as though the child shell terminated by calling _exit(2) with the status 127.

 实例:

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

int main()
{
	pid_t pid = fork();
	if(pid < 0){
		printf("creat fork fault\n");
	}else if(pid > 0){
	
	}else{
		printf("this is child\n");
		system("ls");
	}
	return 0;

}

popen函数

system函数调用shell命令,只能获取到shell命令的返回值,而不能获取shell命令的输出结果,用popen函数可以获取命令的输出结果。

NAME
       popen, pclose - pipe stream to or from a process

SYNOPSIS
       #include <stdio.h>

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

       int pclose(FILE *stream);

DESCRIPTION
       The popen() function opens a process by creating a pipe, fork‐
       ing, and invoking the shell.  Since a pipe  is  by  definition
       unidirectional,  the type argument may specify only reading or
       writing, not both; the  resulting  stream  is  correspondingly
       read-only or write-only.

       The  command argument is a pointer to a null-terminated string
       containing a shell command line.  This command  is  passed  to
       /bin/sh  using  the  -c  flag; interpretation, if any, is per‐
       formed by the shell.

RETURN VALUE
       popen():  on success, returns a pointer to an open stream that
       can be used to read or write to the pipe; if  the  fork(2)  or
       pipe(2) calls fail, or if the function cannot allocate memory,
       NULL is returned.

       pclose(): on success, returns the exit status of the  command;
       if wait4(2) returns an error, or some other error is detected,
       -1 is returned.

       Both functions set errno to an appropriate value in  the  case
       of an error.

 实例

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

int main(void)
{
    char ret[1024] = {0};
    FILE *fp;

    fp = popen("ps","r");
    int nread = fread(ret,1,1024,fp);	

    printf("read ret %d byte, ret=%s\n",nread,ret);
	    
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值