1.介绍
进程创建是操作系统中的一项基本操作,它支持执行新程序和管理系统资源。本文将深入探讨流程创建机制,重点关注理论概念和实际实现细节。
2.概览
2.1 涉及的系统调用
进程创建中涉及的主要系统调用有:
- fork ()
◦通过复制调用进程创建一个新进程
◦子进程返回0,父进程返回子进程的PID
◦内核函数:do_fork() - exec ()
◦用新程序替换当前进程映像
◦多个变体:execve(), execl(), execle(), execv(), execvp(), execvpe()
◦内核函数:do_execve()
2.2 流程创建步骤
- fork
◦重复调用过程
◦创建一个新的过程控制块(PCB)
◦为新进程分配内存
◦复制父的内存空间到子内存空间 - exec
◦用新程序替换子程序的内存空间
◦将程序加载到内存
3.Fork系统调用
3.1 详细说明
fork () 系统调用通过复制调用进程来创建一个新进程。新进程称为子进程,是父进程的精确副本,包括其内存、文件描述符和信号处理程序。唯一的区别是fork () 的返回值,在子进程中为0,而在父进程中为子进程的PID。
3.2 代码例子
一个fork () 用法的简单示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t pid;
// Create a new process
pid = fork();
if (pid < 0) {
// Fork failed
fprintf(stderr, "Fork failed!\n");
return 1;
} else if (pid == 0) {
// Child process
printf("Child process: PID = %d\n", getpid());
printf("Child process: Parent PID = %d\n", getppid());
// Child process can execute a new program using exec()
} else {
// Parent process
printf("Parent process: PID = %d\n", getpid());
printf("Parent process: Child PID = %d\n", pid);
// Wait for the child process to complete
wait(NULL);
printf("Parent process: Child has terminated\n");
}
return 0;
}
4.Exec系统调用
4.1 详细说明
exec () 系统调用用一个新程序替换当前进程映像。这通常在 fork() 之后的子进程中执行,以执行另一个程序。 exec () 函数族包括:
•execve():执行由路径名指定的程序
•execl():执行带有参数列表的程序
•execle():执行带有参数和环境变量列表的程序
•execv():执行带有参数数组的程序
•execvp():执行带有参数列表的程序,在PATH中搜索该程序
•execvpe():执行带有参数和环境变量列表的程序,在PATH中搜索该程序
4.2 代码例子
一个exec() 用法的简单示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t pid;
// Create a new process
pid = fork();
if (pid < 0) {
// Fork failed
fprintf(stderr, "Fork failed!\n");
return 1;
} else if (pid == 0) {
// Child process
printf("Child process: PID = %d\n", getpid());
printf("Child process: Parent PID = %d\n", getppid());
// Execute a new program
char *args[] = {"ls", "-l", NULL};
execvp("ls", args);
// If execvp returns, it must have failed
perror("execvp");
exit(1);
} else {
// Parent process
printf("Parent process: PID = %d\n", getpid());
printf("Parent process: Child PID = %d\n", pid);
// Wait for the child process to complete
wait(NULL);
printf("Parent process: Child has terminated\n");
}
return 0;
}
5.在Linux内核中的进程创建
5.1 内核函数
Linux内核使用几个函数来管理进程的创建:
•do_fork():创建一个新进程
•copy_process():将父进程的状态复制到子进程
•wake_up_new_task():将新进程加入运行队列
•do_execve():加载一个新程序到当前进程
5.2 数据结构
Linux内核使用task_struct结构体来管理进程状态:
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags;
unsigned int ptrace;
int prio, static_prio, normal_prio;
struct list_head tasks;
struct mm_struct *mm, *active_mm;
/* ... many more fields ... */
};
6.进程创建调试
下面是一个全面的进程创建调试器:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
#define MAX_PATH 1024
#define MAX_LINE 256
typedef struct {
pid_t pid;
char state;
unsigned long vm_size;
unsigned long vm_rss;
unsigned long threads;
char name[MAX_LINE];
} ProcessInfo;
// Function to read process information from /proc
void read_process_info(pid_t pid, ProcessInfo* info) {
char path[MAX_PATH];
char line[MAX_LINE];
FILE* fp;
// Read status file
snprintf(path, sizeof(path), "/proc/%d/status", pid);
fp = fopen(path, "r");
if (!fp) return;
info->pid = pid;
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, "State:", 6) == 0) {
info->state = line[7];
} else if (strncmp(line, "VmSize:", 7) == 0) {
sscanf(line, "VmSize: %lu", &info->vm_size);
} else if (strncmp(line, "VmRSS:", 6) == 0) {
sscanf(line, "VmRSS: %lu", &info->vm_rss);
} else if (strncmp(line, "Threads:", 8) == 0) {
sscanf(line, "Threads: %lu", &info->threads);
} else if (strncmp(line, "Name:", 5) == 0) {
sscanf(line, "Name: %s", info->name);
}
}
fclose(fp);
}
// Function to print process state information
void print_process_info(ProcessInfo* info) {
printf("PID: %d\n", info->pid);
printf("Name: %s\n", info->name);
printf("State: %c (", info->state);
switch(info->state) {
case 'R': printf("Running"); break;
case 'S': printf("Sleeping"); break;
case 'D': printf("Disk Sleep"); break;
case 'Z': printf("Zombie"); break;
case 'T': printf("Stopped"); break;
default: printf("Unknown");
}
printf(")\n");
printf("Virtual Memory: %lu KB\n", info->vm_size);
printf("RSS: %lu KB\n", info->vm_rss);
printf("Threads: %lu\n", info->threads);
printf("------------------------\n");
}
// Function to scan all processes
void scan_processes() {
DIR* proc_dir;
struct dirent* entry;
ProcessInfo info;
proc_dir = opendir("/proc");
if (!proc_dir) {
perror("Cannot open /proc");
return;
}
printf("Scanning all processes...\n\n");
while ((entry = readdir(proc_dir))) {
// Check if the entry is a process (directory with numeric name)
if (entry->d_type == DT_DIR) {
char* endptr;
pid_t pid = strtol(entry->d_name, &endptr, 10);
if (*endptr == '\0') { // Valid PID
memset(&info, 0, sizeof(ProcessInfo));
read_process_info(pid, &info);
print_process_info(&info);
}
}
}
closedir(proc_dir);
}
int main() {
scan_processes();
return 0;
}
7.最佳实践
- 状态转换管理
◦始终验证状态转换
◦实现适当的错误处理
◦记录状态变化,以便调试
◦使用原子操作进行状态更新 - 资源管理
◦清理终止状态的资源
◦实现适当的信号处理
◦处理僵尸进程
◦监控资源使用情况 - 性能优化
最小化上下文切换
◦优化流程创建
◦使用合适的调度策略
◦监控系统负载