程序与进程
- 程序:解决某个问题或得到某个结果的可以由计算机等具有信息处理能力的装置执行的代码化指令序列,如: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 terminationSYNOPSIS
#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 stateSYNOPSIS
#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 fileSYNOPSIS
#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 commandSYNOPSIS
#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 processSYNOPSIS
#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;
}