在上一篇 进程概念的介绍 中已经介绍了进程相关的一些函数,这篇文章则介绍进程相关的一些函数。
1、获取进程
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void)
返回:调用者或其父进程 PID
2、创建和终止进程
进程总是处于下面三种状态之一:
- 运行。进程要么在CPU上运行,要么等待被执行且最终会被内核调度。
- 停止。进程的执行被挂起,且不会被调度。当收到 SIGSTOP、SIGTSTP、SIGTTIN或者SIGTOUT信号时,进程就停止,并且保持停止知道它收到一个SIGCONT信号,这时候,进程再次开始运行。
- 终止。进程永远地停止了,进程停止会因为三种原因 1)收到一个信号,2)从主程序返回,return ,3) 调用 exit()、_exit() 函数
创建进程
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回;子进程返回0,父进程返回子进程的PID,出错则返回-1
3、回收子进程
当一个进程终止时,内核不是马上就把它从系统中清除掉,而是保持一种已终止的状态等待父进程回收。如果父进程没有回收,那么就会变为僵尸进程。最终 init 进程会成为其父进程,来回收。那么当一个子进程终止时,父进程怎么可以马上就回收,让系统释放其占有的资源呢,下面介绍两种函数,专门处理这种情况的:
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *statusp, int options);
pid_t wait(int *status);
返回:如果成功,则为子进程的PID,如果出错则为-1
从函数原型可以看出,waitpid() 比wait() 更具灵活性,但也更加复杂。它们的区别我将会在下一篇文章中介绍。
下面是一个示例代码:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#define N 2
int main()
{
int status, i;
pid_t pid[N], retpid;
for (i = 0; i < N; i++)
{
if ( (pid[i] = fork()) == 0) exit(100+i);
}
i = 0;
while ( (retpid = waitpid(pid[i++], &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("child %d terminated normally status=%d\n", retpid, WEXITSTATUS(status));
else
printf("child %d terminated abnormall\n", retpid;
}
if (errno != ECHILD)
fpinntf(stderr, "waitpid error %s\n", strerror(errno));
exit(0);
4、总结
从上文可以看出,创建一个进程并运行并不难,而且各个进程都运行在自己的进程地址空间内,不会像多线程那样共享地址空间,因此就没有多线程那么复杂了,当然相应地进程间的调度会比线程间的切换消耗更加多。当然,要像编写好多进程程序,进程间的通信必不可,后续文章中我也会陆续介绍进程间的通信方式(管道、FIFO、信号量、消息队列、共享内存)。