15、深入理解计算机系统笔记:进程控制

简介: 1、获取进程ID[1] 每个进程都有一个唯一的正数(非0)进程ID(PID)。 示例代码 #include #include pid t getpid(void); pid t getppid(void); returns: PID of either the caller...

1、获取进程ID[1]

每个进程都有一个唯一的正数(非0)进程ID(PID)。

示例代码

#include <unistd.h>
#include <sys/types.h>
pid t getpid(void);
pid t getppid(void);
returns: PID of either the caller or the parent

    The getpid and getppid routines return an integer value of type pid_t, which on Linux systems

is defined in types.h as an int.

进程总是处于运行,停止,终止三种状态间。

2、创建和终止

示例代码

#include <stdlib.h>
void exit(int status);
this function does not return

#include <unistd.h>
#include <sys/types.h>
pid t fork(void);
returns: 0 to child, PID of child to parent, -1 on error

#include <sys/types.h>
#include <sys/wait.h>
pid t waitpid(pid t pid, int *status, int options);
returns: PID of child if OK, 0 (if WNOHANG) or -1 on error
The members of the wait set are determined by the pid argument:
 If pid > 0, then the wait set is the singleton child process whose process ID is equal to pid.
 If pid = -1, then the wait set consists of all of the parent’s child processes.

    The newly created child process is almost, but not quite, identical to the parent. The child

gets an identical (but separate) copy of the parent’s userlevel virtual address space, including the text, data,

and bss segments, heap, and user stack. The child also gets identical copies of any of the parent’s open file descriptors, which

means the child can read and write any files that were open in the parent when it called fork. The most significant

difference between the parent and the newly created child is that they have different

PIDs.

fork函数常令人迷惑,因为它只被调用一次,却会返回两次:一次是在调用进程(父进程)中,一次是在新创建的子进程中。

示例见原文中。

3、回收子进程

进程终止时,内核并不是立即把它从系统中清除;而是保持一种终止状态,直到被父进程回收(reaped)。父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程。一个终止了但仍未被回收的进程称为僵尸进程(zombie)。

如果父进程没有回收,则通过init进程来回收。

一个进程通过调用waitpid函数来等待它的子进程终止或暂停。

4、进程休眠

示例代码

#include <unistd.h>
unsigned int sleep(unsigned int secs);
returns: seconds left to sleep
//让进程挂起一段时间
#include <unistd.h>
int pause(void);
always returns -1
//puts the calling function to sleep until a signal is received by the process.

5、加载并运行程序

示例代码

#include <unistd.h>
int execve(char *filename, char *argv[], char *envp);
does not return if OK, returns -1 on error
int main(int argc, char **argv, char **envp);
int main(int argc, char *argv[], char *envp[]);

在execve加载了filename之后,启动代码准备栈,并将控制传递给新程序的主函数,函数原形如代码中所示。

wps_clip_image-29702wps_clip_image-2126

wps_clip_image-29705

通过getenv,setenv,unsetenv来设备环境变量。

6、进程是执行中程序的一个特殊实例;程序总是运行在某个进程的上下文中。fork函数在新的子进程中运行相同的程序,新的子进程是父进程的一个复制品;execve函数在当前进程的上下文中加载并运行一个新的程序,它会覆盖当前进程的地址空间,但并没有创建一个新进程,新的程序仍然有相同的PID,并且继承了调用execve函数时打开的所有文件描述符。

示例代码

/* $begin shellmain */
#include "csapp.h"
#define MAXARGS   128

/* function prototypes */
void eval(char*cmdline);
int parseline(char *buf, char **argv);
int builtin_command(char **argv); 

int main() 
{
    char cmdline[MAXLINE]; /* command line */

    while (1) {
	/* read */
	printf("> ");                   
	Fgets(cmdline, MAXLINE, stdin); 
	if (feof(stdin))
	    exit(0);

	/* evaluate */
	eval(cmdline);
    } 
}
/* $end shellmain */
  
/* $begin eval */
/* eval - evaluate a command line */
void eval(char *cmdline) 
{
    char *argv[MAXARGS]; /* argv for execve() */
    char buf[MAXLINE];   /* holds modified command line */
    int bg;              /* should the job run in bg or fg? */
    pid_t pid;           /* process id */
    
    strcpy(buf, cmdline);
    bg = parseline(buf, argv); 
    if (argv[0] == NULL)  
	return;   /* ignore empty lines */

    if (!builtin_command(argv)) { 
	if ((pid = Fork()) == 0) {   /* child runs user job */
	    if (execve(argv[0], argv, environ) < 0) {
		printf("%s: Command not found.\n", argv[0]);
		exit(0);
	    }
	}

	/* parent waits for foreground job to terminate */
	if (!bg) {
	    int status;
	    if (waitpid(pid, &status, 0) < 0)
		unix_error("waitfg: waitpid error");
	}
	else
	    printf("%d %s", pid, cmdline);
    }
    return;
}

/* if first arg is a builtin command, run it and return true */
int builtin_command(char **argv) 
{
    if (!strcmp(argv[0], "quit")) /* quit command */
	exit(0);  
    if (!strcmp(argv[0], "&"))    /* ignore singleton & */
	return 1;
    return 0;                     /* not a builtin command */
}
/* $end eval */

/* $begin parseline */
/* parseline - parse the command line and build the argv array */
int parseline(char *buf, char **argv) 
{
    char *delim;         /* points to first space delimiter */
    int argc;            /* number of args */
    int bg;              /* background job? */

    buf[strlen(buf)-1] = ' ';  /* replace trailing '\n' with space */
    while (*buf && (*buf == ' ')) /* ignore leading spaces */
	buf++;

    /* build the argv list */
    argc = 0;
    while ((delim = strchr(buf, ' '))) {
	argv[argc++] = buf;
	*delim = '\0';
	buf = delim + 1;
	while (*buf && (*buf == ' ')) /* ignore spaces */
	       buf++;
    }
    argv[argc] = NULL;
    
    if (argc == 0)  /* ignore blank line */
	return 1;

    /* should the job run in the background? */
    if ((bg = (*argv[argc-1] == '&')) != 0)
	argv[--argc] = NULL;

    return bg;
}
/* $end parseline */

<Computer Systems:A Programmer's Perspective>

注:[1] 原书8.4节有详细的论述。

目录
相关文章
|
12月前
|
监控 关系型数据库 MySQL
在CentOS系统中,如何统计哪个进程打开了文件描述符?
利用上述方法,你可以有效地监控和统计CentOS系统中的进程打开的文件描述符数量,以帮助排查错误或优化系统配置。通过组合使用各种工具和命令,可以获得对系统状态和行为的深入了解,进而做出相应的调整和
467 5
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第7天】麒麟系统mate-indicators进程占用内存过高问题解决
2011 2
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
3638 58
|
弹性计算 运维 监控
基于进程热点分析与系统资源优化的智能运维实践
智能服务器管理平台提供直观的可视化界面,助力高效操作系统管理。核心功能包括运维监控、智能助手和扩展插件管理,支持系统健康监控、故障诊断等,确保集群稳定运行。首次使用需激活服务并安装管控组件。平台还提供进程热点追踪、性能观测与优化建议,帮助开发人员快速识别和解决性能瓶颈。定期分析和多维度监控可提前预警潜在问题,保障系统长期稳定运行。
732 17
|
监控 搜索推荐 开发工具
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
4311 2
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
881 13
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
2080 1
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
|
监控 API
【原创】用Delphi编写系统进程监控程序
【原创】用Delphi编写系统进程监控程序
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第5天】麒麟系统mate-indicators进程占用内存过高问题解决
2000 0