《Linux/UNIX系统编程手册》第28章 详述进程创建和程序执行
关键词:acct()、clone()、fork()/vfork()等等。
内核对进程记账会使系统在每个进程结束后记录一条账单信息。
Linux通过fork()、vfork()、clone()创建进程,其中clone()提供了更为精细的控制。
接着比较了fork()、vfork()、clone()、fork()+exec()、vfork()+exec()创建进程熟读和虚拟内存消耗总量。
exec()执行新程序替换当前进程,然后详细比较了exec()和fork()两者对创建进程属性的影响。
1. 进程记账
内核对进程记账的信息包括终止状态以及进程消耗的CPU时间。
特权进程可利用acct()来打开和关闭进程记账功能。
#define _BSD_SOURCE #include <unistd.h> int acct(const char *acctfile); Returns 0 on success, or –1 on error
2. 系统调用clone()
类似于fork()和vfork(),clone()也能创建一个新进程,clone()对进程创建步骤控制更为精准。
#define _GNU_SOURCE #include <sched.h> int clone(int (*func) (void *), void *child_stack, int flags, void *func_arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ ); Returns process ID of child on success, or –1 on error
clone()创建的新锦成几近于父进程的翻版,但是子进程继续运行时不以调用处为起点,转而去调用参数func所指定的函数。
调用者必须分配一块大小适中的内存空间供子进程的栈使用,同时将这块内存的指针置于参数child_stack中。child_stack应当指向所分配内存块的高端。
flags低字节中存放着子进程的中职信号,剩余字节存放掩码,用于控制clone()操作。
剩余参数ptkd、tls、ctid与线程的实现相关。
#define _GNU_SOURCE #include <signal.h> #include <sys/wait.h> #include <fcntl.h> #include <sched.h> #include "tlpi_hdr.h" #ifndef CHILD_SIG #define CHILD_SIG SIGUSR1 /* Signal to be generated on termination of cloned child */ #endif static int /* Startup function for cloned child */ childFunc(void *arg) { if (close(*((int *) arg)) == -1) errExit("close"); return 0; /* Child terminates now */ } int main(int argc, char *argv[]) { const int STACK_SIZE = 65536; /* Stack size for cloned child */ char *stack; /* Start of stack buffer */ char *stackTop; /* End of stack buffer */ int s, fd, flags; fd = open("/dev/null", O_RDWR); /* Child will close this fd */ if (fd == -1) errExit("open"); /* If argc > 1, child shares file descriptor table with parent */ flags = (argc > 1) ? CLONE_FILES : 0;-----------------------------------使用CLONE_FILES之后,父子进程共享同一个文件描述符表。 /* Allocate stack for child */ stack = malloc(STACK_SIZE); if (stack == NULL) errExit("malloc"); stackTop = stack + STACK_SIZE; /* Assume stack grows downward */---分配一个栈供子进程使用,并将高地址作为栈开始。 /* Ignore CHILD_SIG, in case it is a signal whose default is to terminate the process; but don't ignore SIGCHLD (which is ignored by default), since that would prevent the creation of a zombie. */ if (CHILD_SIG != 0 && CHILD_SIG != SIGCHLD) if (signal(CHILD_SIG, SIG_IGN) == SIG_ERR) errExit("signal"); /* Create child; child commences execution in childFunc() */ if (clone(childFunc, stackTop, flags | CHILD_SIG, (void *) &fd) == -1)--创建子进程。 errExit("clone"); /* Parent falls through to here. Wait for child; __WCLONE is needed for child notifying with signal other than SIGCHLD. */ if (waitpid(-1, NULL, (CHILD_SIG != SIGCHLD) ? __WCLONE : 0) == -1)------等待子进程终止。 errExit("waitpid"); printf("child has terminated\n"); /* Did close() of file descriptor in child affect parent? */ s = write(fd, "x", 1);---------------------------------------------------调用write()检查文件描述符是否仍处于打开状态。 if (s == -1 && errno == EBADF) printf("file descriptor %d has been closed\n", fd); else if (s == -1) printf("write() on file descriptor %d failed " "unexpectedly (%s)\n", fd, strerror(errno)); else printf("write() on file descriptor %d succeeded\n", fd); exit(EXIT_SUCCESS); }
Linux Threads线程实现使用clone()来创建线程:CLONE_VM|CLONE_FILES|CLONE_FS|CLONE_SIGHAND。
3. 进程的创建速度
x86 32系统,内核2.6.27测试数据:
第1行进程所占内存越大,fork()所需时间越长。额外时间花在了为子进程复制页表、将数据段、堆栈页表标记为只读的工作上。
第2行尽管进程的虚拟内存总量在增加,但所使用的时间保持不变。因为vfork()并未复制页表或页,调用进程的虚拟内存总大小并未造成影响。
第3行clone()使用CLONE_VM|CLONE_VFORK|CLONE_FS|CLONE_SIGHAND|CLONE_FILES,前两个模拟vfork(),剩余则要求父子进程共享文件系统属性、信号处置表、打开文件描述符表。和vfork()之间的差值表示了这些额外工作的开销。
第4行和第2行的差值,说明执行新程序的开销。
第5行和第3行的差值,说明执行新程序的开销。
4. exec()和fork()对进程属性的影响
fork()、vfork()、clone()使用do_fork()系统调用,和exec()有较大差异。
下表详细描述了exec()和fork()对进程属性的影响:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)