您好,登录后才能下订单哦!
# Linux进程怎么创建和启动
## 1. 进程基础概念
### 1.1 什么是进程
进程(Process)是Linux系统中程序执行的基本单位,它是操作系统资源分配和调度的独立实体。每个进程都有自己独立的地址空间、堆栈、文件描述符等系统资源。
进程与程序的区别:
- 程序是静态的存储在磁盘上的可执行文件
- 进程是程序在内存中的动态执行实例
### 1.2 进程的生命周期
Linux进程通常经历以下状态变化:
1. 创建(Created)
2. 就绪(Ready)
3. 运行(Running)
4. 阻塞(Blocked)
5. 终止(Terminated)
## 2. 进程创建机制
### 2.1 fork()系统调用
`fork()`是Linux创建新进程的基本方式:
```c
#include <unistd.h>
pid_t fork(void);
工作原理: 1. 复制父进程的地址空间、堆栈、文件描述符等 2. 创建新的进程控制块(PCB) 3. 返回两次: - 父进程中返回子进程PID - 子进程中返回0
示例代码:
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return 1;
} else if (pid == 0) {
printf("This is child process (PID: %d)\n", getpid());
} else {
printf("This is parent process (PID: %d), child PID: %d\n",
getpid(), pid);
}
return 0;
}
现代Linux系统采用写时复制优化fork()性能: - 父子进程最初共享相同的物理内存页 - 只有当任一进程尝试修改内存页时,才会复制该页 - 显著减少fork()的开销
exec
函数族用于将当前进程映像替换为新的程序:
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
典型使用模式:
pid_t pid = fork();
if (pid == 0) {
// 子进程
execl("/bin/ls", "ls", "-l", NULL);
perror("exec failed");
exit(1);
}
Linux标准进程创建流程: 1. 父进程调用fork()创建子进程 2. 子进程调用exec()加载新程序 3. 父进程通过wait()等待子进程结束
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// 子进程
execlp("ls", "ls", "-l", NULL);
perror("exec failed");
return 1;
} else if (pid > 0) {
// 父进程
int status;
waitpid(pid, &status, 0);
printf("Child process exited with status %d\n", WEXITSTATUS(status));
} else {
perror("fork failed");
return 1;
}
return 0;
}
简化版的进程创建和启动:
#include <stdlib.h>
int system(const char *command);
示例:
#include <stdlib.h>
int main() {
int ret = system("ls -l /");
printf("Command exited with status %d\n", ret);
return 0;
}
注意:system()会创建shell进程来执行命令,存在安全风险。
更高效的进程创建方式:
#include <spawn.h>
int posix_spawn(pid_t *pid, const char *path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *attrp,
char *const argv[], char *const envp[]);
优点: - 合并了fork和exec操作 - 允许更精细控制文件描述符和属性
提供更灵活的进程创建:
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...);
特点: - 可以控制共享哪些资源 - 用于实现线程(轻量级进程)
重要环境变量: - PATH:命令搜索路径 - LD_LIBRARY_PATH:动态库搜索路径 - HOME:用户主目录
启动后台进程:
command &
创建守护进程: 1. fork()创建子进程 2. 子进程调用setsid()创建新会话 3. 改变工作目录到/ 4. 重定向标准I/O 5. 处理信号
影响因素: - 进程地址空间大小 - 页表复制开销 - 写时复制触发频率
优化策略: - 减少不必要的fork() - 使用vfork()(已过时,不推荐) - 考虑posix_spawn()
影响因素: - 程序文件大小 - 动态链接库数量 - 环境变量数量
优化策略: - 静态链接减少动态库加载 - 精简环境变量 - 使用execve()直接指定环境
设置资源限制:
#include <sys/resource.h>
setrlimit(RLIMIT_CPU, &limit);
常见限制类型: - CPU时间 - 内存使用 - 文件大小 - 进程数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAX_ARGS 20
void parse_command(char *cmd, char **argv) {
char *token = strtok(cmd, " ");
int i = 0;
while (token != NULL && i < MAX_ARGS-1) {
argv[i++] = token;
token = strtok(NULL, " ");
}
argv[i] = NULL;
}
int main() {
char cmd[256];
char *argv[MAX_ARGS];
while (1) {
printf("mysh> ");
if (fgets(cmd, sizeof(cmd), stdin) == NULL) {
break;
}
cmd[strcspn(cmd, "\n")] = '\0'; // 移除换行符
if (strlen(cmd) == 0) continue;
parse_command(cmd, argv);
if (strcmp(argv[0], "exit") == 0) {
break;
}
pid_t pid = fork();
if (pid == 0) {
execvp(argv[0], argv);
perror("exec failed");
exit(1);
} else if (pid > 0) {
wait(NULL);
} else {
perror("fork failed");
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define POOL_SIZE 5
void worker(int id) {
printf("Worker %d (PID: %d) started\n", id, getpid());
sleep(3);
printf("Worker %d (PID: %d) finished\n", id, getpid());
exit(0);
}
int main() {
int i;
pid_t pids[POOL_SIZE];
// 创建工作进程
for (i = 0; i < POOL_SIZE; i++) {
pids[i] = fork();
if (pids[i] == 0) {
worker(i);
} else if (pids[i] < 0) {
perror("fork failed");
exit(1);
}
}
// 等待所有工作进程结束
for (i = 0; i < POOL_SIZE; i++) {
waitpid(pids[i], NULL, 0);
}
printf("All workers completed\n");
return 0;
}
使用strace跟踪:
strace -f -e trace=process command
pstree -p
使用time测量:
time command
使用perf分析:
perf stat command
Linux进程创建和启动涉及多个关键系统调用和复杂机制:
掌握这些知识对于Linux系统编程、性能优化和安全加固都至关重要。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。