进程学习

概述

进程是系统和网络编程的一个重要概念,把比较重要的知识点记录下来.

获取进程ID

每个进程都有一个唯一的正数(非零)进程ID(PID).getpid函数返回调用进程的PID.getppid函数返回它的父进程的PID(创建调用进程的进程).

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

pid_t getpid(void);
pid_t getppid(void);

getpid和getppid函数返回一个类型为pid_t的整数值,在Linux系统上它在types.h中被定义为int.

创建进程

父进程通过调用fork函数创建一个新的运行的子程序.

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

pid_t fork(void);

注:子进程返回0,父进程返回子进程的PID,如果出错,则为-1.

fork函数有以下几个特点:

  1. fork函数被父进程调用一次,但是却返回两次 — 一次是返回到父进程,一次是返回到新创建的子进程.
  2. 父进程和子进程是并发运行的独立进程.内核能够以任意方式交替执行它们的逻辑控制流中的指令.
  3. 父进程和子进程的地址空间都是相同的,每个进程有相同的用户栈,相同的本地变量值,相同的堆,相同的全局变量值.
  4. 父进程和子进程共享文件.子进程继承了父进程所有的打开文件.

区别:父进程和子进程之间最大的区别在于它们有不同的PID.

下面这个程序说明了fork函数的特点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

pid_t Fork(void);

int main(void)
{
pid_t pid;
int x = 1;

pid = Fork();
if(pid == 0){
printf("p1: x = %d\n",++x);
}
printf("p2: x = %d\n",--x);
exit(0);
}

pid_t Fork(void)
{
pid_t pid;

if((pid = fork()) < 0){
fprintf(stderr,"fork error: %s\n",strerror(errno));
exit(0);
}
return pid;
}

上面程序工作原理如下:

                      p1: x = 2        p2: x = 1
             --------------->'-------------->'------------->'          子进程
             |            printf          printf          exit
             |
             |
   x == 1    |        p2: x = 0
 '----------->'------------->'-------------->'                         父进程
main       fork           printf          exit

子进程输出:

p1: x = 2
p2: x = 1

父进程输出:

p2: x = 0

终止进程

调用exit函数终止进程

#include <stdlib.h>

void exit(int status);

回收子进程

一个进程可以通过调用waitpid函数来等待它的子进程终止或者停止.

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

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

另外,wait函数是waitpid函数的简单版本:

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

pid_t wait(int *statusp);

进程休眠

sleep函数将一个进程挂起一段指定时间:

#include <unistd.h>

unsigned int sleep(unsigned int secs);

还有一个pause函数,该函数让调用函数休眠,直到该进程收到一个信号.

#include <unistd.h>

int pause(void);

加载并运行程序

execve函数在当前进程的上下文中加载并运行一个新程序.

#include <unistd.h>

int execve(const char *filename, const char *argv[], const char *envp[]);