第1关:获取进程常见属性
任务描述
在 Linux
环境下,进程是一个十分重要的概念。每个进程都由一个唯一的标识符来表示,即进程ID
,通常称为pid
。本关将介绍如何获取进程的pid
。
本关任务:学会使用C
语言在Linux
系统中获取进程的pid
以及父进程的pid
。
相关知识
Linux
系统中存在一个特殊的进程,即空闲进程(idle process
),当没有其他进程在运行时,内核所运行的进程就是空闲进程,它的pid
为0
。在启动后,内核运行的第一个进程称为init
进程,它的pid
是1
。通常,Linux
系统中init
进程就是我们在资源管理器中看到的名为init
的程序。系统中其它的进程都是由init
来创建出来的。
创建新进程的那个进程被称为父进程,而新创建的进程被称为子进程。每个进程都是由其他进程创建的(除了init
进程),因此每个子进程都有一个父进程。
Linux
系统提供了两个系统调用函数来获取一个进程的pid
和其父进程的pid
,分别是getpid
和getppid
函数。在Linux
系统中可以使用man
命令来查询这些函数的使用方法。具体的查询命令为: man 2 函数名
获取进程自身pid
获取进程本身的进程ID
的系统调用函数是getpid
,具体的说明如下:
-
需要的头文件如下:
#include <sys/types.h>
#include <unistd.h>
-
函数格式如下:
pid_t getpid(void);
-
函数返回值说明: 返回当前进程的
pid
值。
案例演示1
: 编写一个程序,打印自身的进程ID
。详细代码如下所示:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = getpid();
printf("当前进程的ID为:%d\n", pid);
return 0;
}
将以上代码保存为getpid.c
文件,编译执行。可以看到每次运行都打印出不同的进程ID
,这是因为Linux
系统动态的给进程分配pid
。
获取父进程pid
获取父进程的进程ID
的系统调用函数是getppid
,具体的说明如下:
-
需要的头文件如下:
#include <sys/types.h>
#include <unistd.h>
-
函数格式如下:
pid_t getppid(void);
-
函数返回值说明: 返回当前进程的父进程的
pid
值。
案例演示1
: 编写一个程序,打印父进程ID
和自身进程ID
。详细代码如下所示:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = getpid();
printf("当前进程的ID为:%d\n", pid);
pid_t ppid = getppid();
printf("当前进程的父进程ID为:%d\n", ppid);
return 0;
}
将以上代码保存为getppid.c
文件,编译执行。可以看到每次运行都打印出相同的父进程ID
,这是因为我们在同一个终端中运行3
次程序,所以被运行的程序父进程为终端进程,因为父进程一直都一样。
编程要求
本关的编程任务是补全右侧代码片段中Begin
至End
中间的代码,具体要求如下:
- 补全
getProcInfo
函数,用于获取当前进程ID
和其父进程ID
(提示:将结果存放在procIDInfo结构体中)。
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
/**********************
* pid: 当前进程ID
* ppid: 父进程ID
***********************/
struct procIDInfo
{
pid_t pid;
pid_t ppid;
};
/************************
* 返回值: 需要被打开的目录路径
*************************/
struct procIDInfo getProcInfo()
{
struct procIDInfo ret; //存放进程ID信息,并返回
/********** BEGIN **********/
ret.pid= getpid();
ret.ppid=getppid();
/********** END **********/
return ret;
}
第2关:进程创建操作-fork
编程要求
本关的编程任务是补全右侧代码片段中Begin
至End
中间的代码,具体要求如下:
- 补全
createProcess
函数,使用fork
函数创建进程,并在子进程中输出"Children"
字符串,在父进程中输出"Parent"
字符串。(注意:不要在createProcess
函数中使用exit
函数或者return
来退出程序)。 -
#include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <string.h> #include <errno.h> /************************ * 提示: 不要在子进程或父进程中使用exit函数或者return来退出程序 *************************/ void createProcess() { /********** BEGIN **********/ pid_t pid=fork(); if(pid==-1) { printf("创建进程失败(%s)!\n", strerror(errno)); } else if(!pid) { printf("Children",getpid(),getppid()); } else { printf("Parent",getpid(),getppid()); } /********** END **********/ }
第3关:进程创建操作-vfork
-
编程要求
本关的编程任务是补全右侧代码片段中
Begin
至End
中间的代码,具体要求如下: - 补全
createProcess
函数,使用vfork
函数创建进程,并在子进程中输出"Children"字符串(提示:需要换行),在父进程中输出"Parent"字符串(提示:需要换行)。#include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> /************************ * 提示: 不要在子进程中使用return来退出程序 *************************/ void createProcess() { /********** BEGIN **********/ pid_t pid=vfork(); if(pid==-1) { printf("创建进程失败(%s)!\n", strerror(errno)); } else if(!pid) { sleep(2); printf("Children\n",getpid(),getppid()); } else { printf("Parent\n",getpid(),getppid()); } /********** END **********/ exit(0); }
第4关:进程终止
-
编程要求
本关的编程任务是补全右侧代码片段中
Begin
至End
中间的代码,具体要求如下: - 补全
exitProcess
函数,使用atexit
函数注册一个函数,在注册函数中打印出当前进程的ID
号。 -
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
/************************
* 提示: 用户需要在exitProcess函数中使用atexit函数注册一个自定义函数,并在自定义函数中打印出当前进程ID号
*************************/
void out()
{
printf("%d\n",getpid());
}
void exitProcess()
{
/********** BEGIN **********/
if(atexit(out)!=0)
{
printf("调用atexit函数错误\n");
}
}