C++进程编程完整面试指南
目录
1. 进程基础概念
1.1 进程 vs 线程
特性 | 进程 | 线程 |
---|---|---|
内存空间 | 独立的虚拟地址空间 | 共享进程的地址空间 |
创建开销 | 大(需要复制页表等) | 相对较小 |
通信方式 | IPC机制(管道、共享内存等) | 直接访问共享变量 |
安全性 | 进程间相互隔离 | 一个线程崩溃可能影响整个进程 |
资源消耗 | 内存消耗大 | 内存消耗小 |
切换成本 | 高(需要切换页表) | 低(只需切换寄存器) |
1.2 进程的内存布局
高地址
┌─────────────┐
│ 内核空间 │ <- 内核代码和数据
├─────────────┤
│ 栈 │ <- 局部变量、函数参数(向下增长)
│ ↓ │
│ │
│ ↑ │
│ 堆 │ <- 动态分配内存(向上增长)
├─────────────┤
│ BSS段 │ <- 未初始化全局变量
├─────────────┤
│ 数据段 │ <- 已初始化全局变量
├─────────────┤
│ 代码段 │ <- 程序代码(只读)
└─────────────┘
低地址
1.3 进程控制块(PCB)
进程控制块包含的信息:
- 进程标识符(PID)
- 进程状态
- 程序计数器
- CPU寄存器
- CPU调度信息
- 内存管理信息
- 记账信息
- I/O状态信息
2. 进程创建与管理
2.1 fork()系统调用
cpp
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
int main() {
pid_t pid = fork();
if (pid < 0) {
// fork失败
perror("fork failed");
return 1;
} else if (pid == 0) {
// 子进程
std::cout << "Child process: PID = " << getpid()
<< ", PPID = " << getppid() << std::endl;
// 子进程的工作
sleep(2);
std::cout << "Child process finished" << std::endl;
} else {
// 父进程,pid是子进程的PID
std::cout << "Parent process: PID = " << getpid()
<< ", Child PID = " << pid << std::endl;
// 等待子进程结束
int status;
wait(&status);
std::cout << "Child process exited with status: "
<< WEXITSTATUS(status) << std::endl;
}
return 0;
}
2.2 exec族函数
exec函数族用于在当前进程中执行新程序:
cpp
#include <unistd.h>
// 常用的exec函数
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
// 示例:创建子进程执行ls命令
if (fork() == 0) {
execl("/bin/ls", "ls", "-l", NULL);
// 如果exec成功,这行代码不会执行
perror("exec failed");
exit(1);
}
2.3 wait()和waitpid()
cpp
#include <sys/wait.h>
// 等待任意子进程
pid_t wait(int *status);
// 等待指定子进程
pid_t waitpid(pid_t pid, int *status, int options);
// 示例
int main() {
pid_t pid = fork();
if (pid == 0) {
// 子进程
sleep(3);
exit(42); // 以状态码42退出
} else {
// 父进程
int status;
pid_t child_pid = wait(&status);
if (WIFEXITED(status)) {
printf("Child %d exited with status %d\n",
child_pid, WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("Child %d killed by signal %d\n",
child_pid, WTERMSIG(status));
}
}
return 0;
}
3. 进程继承机制
3.1 fork()后子进程继承的内容
完全继承:
- 用户ID和组ID
- 环境变量
- 工作目录
- 根目录
- 文件创建掩码(umask)
- 信号处理设置
- 打开的文件描述符
- 进程组ID
- 会话ID
部分继承/修改:
- 进程ID(子进程获得新的PID)
- 父进程ID(子进程的PPID是父进程的PID)
- 进程运行时间(重置为0)
- 挂起的信号(清空)
- 文件锁(不继承)
3.2 写时复制(Copy-on-Write)
cpp
#include <unistd.h>
#include <iostream>
int global_var = 100;
int main() {
int local_var = 200;
pid_t pid = fork();
if (pid == 0) {
// 子进程
std::cout << "Child - global_var: " << global_var
<< ", local_var: " << local_var << std::endl;
// 修改变量,触发写时复制
global_var = 300;
local_var = 400;
std::cout << "Child after modification - global_var: "
<< global_var << ", local_var: " << local_var << std::endl;
} else {
// 父进程等待子进程完成
wait(NULL);
std::cout << "Parent - global_var: " << global_var
<< ", local_var: " << local_var << std::endl;
// 父进程中的变量值不受子进程影响
}
return 0;
}
3.3 文件描述符继承
cpp
#include <fcntl.h>
#include <unistd.h>
int main() {
// 父进程打开文件
int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fork() == 0) {
// 子进程继承了文件描述符
write(fd, "Child process\n", 14);
close(fd);
} else {
// 父进程
write(fd, "Parent process\n", 15);
close(fd);
wait(NULL);
}
return 0;
}
4. 进程间通信(IPC)
4.1 管道(Pipe)
匿名管道:
cpp
#include <unistd.h>
int main() {
int pipefd[2]; // pipefd[0]读端,pipefd[1]写端
char buffer[100];
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
pid_t pid = fork();
if (pid == 0) {
// 子进程:写数据
close(pipefd[0]); // 关闭读端
write(pipefd[1], "Hello from child", 16);
close(pipefd[1]);
} else {
// 父进程:读数据
close(pipefd[1]); // 关闭写端
int n = read(pipefd[0], buffer, sizeof(buffer));
buffer[n] = '\0';
printf("Parent received: %s\n", buffer);
close(pipefd[0]);
wait(NULL);
}
return 0;
}
命名管道(FIFO):
cpp
#include <sys/stat.h>
#include <fcntl.h>
// 创建命名管道
int mkfifo(const char *pathname, mode_t mode);
// 使用示例
int main() {
const char* fifo_path = "/tmp/myfifo";
// 创建命名管道
if (mkfifo(fifo_path, 0666) == -1) {
perror("mkfifo");
return 1;
}
if (fork() == 0) {
// 子进程:写入数据
int fd = open(fifo_path, O_WRONLY);
write(fd, "Hello FIFO", 10);
close(fd);
} else {
// 父进程:读取数据
char buffer[100];
int fd = open(fifo_path, O_RDONLY);
int n = read(fd, buffer, sizeof(buffer));
buffer[n] = '\0';
printf("Received: %s\n", buffer);
close(fd);
wait(NULL);
unlink(fifo_path); // 删除命名管道
}
return 0;
}
4.2 共享内存
cpp
#include <sys/shm.h>
#include <sys/ipc.h>
struct shared_data {
int counter;
char message[100];
};
int main() {
key_t key = ftok(".", 'a'); // 生成键值
// 创建共享内存段
int shmid = shmget(key, sizeof(shared_data), IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget");
return 1;
}
// 连接共享内存
shared_data* data = (shared_data*)shmat(shmid, NULL, 0);
if (data == (void*)-1) {
perror("shmat");
return 1;
}
if (fork() == 0) {
// 子进程
data->counter = 42;
strcpy(data->message, "Hello from child");
// 分离共享内存
shmdt(data);
} else {
// 父进程
wait(NULL); // 等待子进程完成
printf("Counter: %d\n", data->counter);
printf("Message: %s\n", data->message);
// 分离并删除共享内存
shmdt(data);
shmctl(shmid, IPC_RMID, NULL);
}
return 0;
}
4.3 消息队列
cpp
#include <sys/msg.h>
struct msg_buffer {
long msg_type;
char msg_text[100];
};
int main() {
key_t key = ftok(".", 'b');
// 创建消息队列
int msgid = msgget(key, IPC_CREAT | 0666);
if (msgid == -1) {
perror("msgget");
return 1;
}
if (fork() == 0) {
// 子进程:发送消息
msg_buffer message;
message.msg_type = 1;
strcpy(message.msg_text, "Hello from child process");
if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {
perror("msgsnd");
}
} else {
// 父进程:接收消息
msg_buffer message;
if (msgrcv(msgid, &message, sizeof(message.msg_text), 1, 0) == -1) {
perror("msgrcv");
} else {
printf("Received: %s\n", message.msg_text);
}
wait(NULL);
// 删除消息队列
msgctl(msgid, IPC_RMID, NULL);
}
return 0;
}
4.4 信号量
cpp
#include <sys/sem.h>
// 信号量操作结构
struct sembuf {
unsigned short sem_num; // 信号量编号
short sem_op; // 操作值
short sem_flg; // 操作标志
};
int main() {
key_t key = ftok(".", 'c');
// 创建信号量集
int semid = semget(key, 1, IPC_CREAT | 0666);
if (semid == -1) {
perror("semget");
return 1;
}
// 初始化信号量值为1
if (semctl(semid, 0, SETVAL, 1) == -1) {
perror("semctl");
return 1;
}
if (fork() == 0) {
// 子进程
struct sembuf sem_op;
// P操作(等待)
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = 0;
semop(semid, &sem_op, 1);
// 临界区
printf("Child in critical section\n");
sleep(2);
// V操作(信号)
sem_op.sem_op = 1;
semop(semid, &sem_op, 1);
} else {
// 父进程类似操作
sleep(1); // 稍后开始
struct sembuf sem_op;
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = 0;
semop(semid, &sem_op, 1);
printf("Parent in critical section\n");
sem_op.sem_op = 1;
semop(semid, &sem_op, 1);
wait(NULL);
// 删除信号量
semctl(semid, 0, IPC_RMID);
}
return 0;
}
5. 进程同步与控制
5.1 信号处理
cpp
#include <signal.h>
// 信号处理函数
void signal_handler(int signum) {
printf("Received signal %d\n", signum);
if (signum == SIGINT) {
printf("Ctrl+C pressed, exiting gracefully...\n");
exit(0);
}
}
int main() {
// 注册信号处理函数
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
pid_t pid = fork();
if (pid == 0) {
// 子进程
sleep(2);
kill(getppid(), SIGUSR1); // 向父进程发送SIGUSR1信号
exit(0);
} else {
// 父进程
printf("Parent process PID: %d\n", getpid());
printf("Press Ctrl+C to exit, or wait for child signal...\n");
// 等待信号
while (1) {
pause(); // 暂停直到收到信号
}
}
return 0;
}
5.2 进程组和会话
cpp
#include <unistd.h>
int main() {
printf("Initial: PID=%d, PGID=%d, SID=%d\n",
getpid(), getpgrp(), getsid(0));
pid_t pid = fork();
if (pid == 0) {
// 子进程创建新的进程组
setpgid(0, 0); // 将自己设为进程组长
printf("Child: PID=%d, PGID=%d, SID=%d\n",
getpid(), getpgrp(), getsid(0));
// 创建新会话
if (setsid() != -1) {
printf("New session: PID=%d, PGID=%d, SID=%d\n",
getpid(), getpgrp(), getsid(0));
}
} else {
wait(NULL);
printf("Parent: PID=%d, PGID=%d, SID=%d\n",
getpid(), getpgrp(), getsid(0));
}
return 0;
}
6. 进程状态与调度
6.1 进程状态
┌─────────┐ fork() ┌─────────┐
│ 不存在 │ ─────────→ │ 创建 │
└─────────┘ └─────────┘
│
↓
┌─────────┐
┌─→ │ 就绪 │ ←─┐
│ └─────────┘ │
│ │ │
│ 时间片 │ 调度 │ I/O完成
│ 用完 ↓ │ 或事件
│ ┌─────────┐ │
└── │ 运行 │ ──┘
└─────────┘
│
│ 等待I/O或事件
↓
┌─────────┐
│ 阻塞 │
└─────────┘
│
│ exit()
↓
┌─────────┐
│ 终止 │
└─────────┘
6.2 优先级和调度策略
cpp
#include <sched.h>
#include <sys/resource.h>
int main() {
// 获取和设置进程优先级
int priority = getpriority(PRIO_PROCESS, 0);
printf("Current priority: %d\n", priority);
// 设置更高优先级(需要权限)
if (setpriority(PRIO_PROCESS, 0, priority - 1) == -1) {
perror("setpriority");
}
// 获取调度策略
int policy = sched_getscheduler(0);
switch (policy) {
case SCHED_OTHER:
printf("Scheduling policy: SCHED_OTHER\n");
break;
case SCHED_FIFO:
printf("Scheduling policy: SCHED_FIFO\n");
break;
case SCHED_RR:
printf("Scheduling policy: SCHED_RR\n");
break;
}
return 0;
}
7. 高级进程编程
7.1 守护进程(Daemon)
cpp
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
void create_daemon() {
pid_t pid = fork();
if (pid < 0) exit(1); // fork失败
if (pid > 0) exit(0); // 父进程退出
// 子进程继续
if (setsid() < 0) exit(1); // 创建新会话
// 忽略信号
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
// 再次fork
pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0);
// 设置文件权限掩码
umask(0);
// 改变工作目录
chdir("/");
// 关闭文件描述符
for (int fd = sysconf(_SC_OPEN_MAX); fd >= 0; fd--) {
close(fd);
}
// 重定向标准输入输出到/dev/null
open("/dev/null", O_RDWR); // stdin
dup(0); // stdout
dup(0); // stderr
}
int main() {
create_daemon();
// 守护进程工作循环
while (1) {
// 执行守护进程任务
sleep(30);
}
return 0;
}
7.2 进程池
cpp
#include <vector>
#include <queue>
#include <sys/socket.h>
class ProcessPool {
private:
std::vector<pid_t> workers;
int listen_fd;
int worker_count;
public:
ProcessPool(int count, int port) : worker_count(count) {
// 创建监听socket
listen_fd = create_listen_socket(port);
// 创建工作进程
for (int i = 0; i < worker_count; i++) {
pid_t pid = fork();
if (pid == 0) {
// 子进程:工作进程
worker_process();
exit(0);
} else if (pid > 0) {
workers.push_back(pid);
}
}
}
void worker_process() {
while (true) {
int client_fd = accept(listen_fd, NULL, NULL);
if (client_fd > 0) {
handle_client(client_fd);
close(client_fd);
}
}
}
void handle_client(int client_fd) {
// 处理客户端请求
char buffer[1024];
int n = read(client_fd, buffer, sizeof(buffer));
if (n > 0) {
// 处理数据
write(client_fd, "HTTP/1.1 200 OK\r\n\r\nHello\n", 26);
}
}
~ProcessPool() {
// 终止所有工作进程
for (pid_t pid : workers) {
kill(pid, SIGTERM);
waitpid(pid, NULL, 0);
}
close(listen_fd);
}
};
7.3 僵尸进程和孤儿进程处理
cpp
#include <signal.h>
// 处理SIGCHLD信号,避免僵尸进程
void sigchld_handler(int sig) {
pid_t pid;
int status;
// 回收所有可用的子进程
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
printf("Child process %d terminated\n", pid);
}
}
int main() {
// 注册SIGCHLD信号处理函数
signal(SIGCHLD, sigchld_handler);
// 创建多个子进程
for (int i = 0; i < 5; i++) {
pid_t pid = fork();
if (pid == 0) {
// 子进程工作
printf("Child %d working...\n", getpid());
sleep(rand() % 10 + 1); // 随机工作时间
printf("Child %d finished\n", getpid());
exit(i);
}
}
// 父进程继续工作
printf("Parent process continues...\n");
sleep(15);
return 0;
}
8. 常见面试题汇总
8.1 基础概念题
Q1: 进程和线程的区别是什么?
- 内存空间:进程独立,线程共享
- 创建开销:进程大,线程小
- 通信方式:进程需要IPC,线程直接共享内存
- 安全性:进程隔离性好,线程安全性差
Q2: fork()函数的返回值是什么?
- 父进程中返回子进程的PID(>0)
- 子进程中返回0
- 失败时返回-1
Q3: 什么是写时复制(COW)?
- fork()后父子进程共享物理内存页
- 只有在写入时才复制页面
- 节省内存,提高fork效率
8.2 进程通信题
Q4: IPC方式有哪些?各有什么特点?
IPC方式 | 特点 | 适用场景 |
---|---|---|
管道 | 简单,单向,有血缘关系 | 父子进程通信 |
命名管道 | 双向,无血缘关系限制 | 任意进程通信 |
共享内存 | 速度最快,需要同步 | 大量数据交换 |
消息队列 | 有格式,异步 | 结构化数据传递 |
信号量 | 用于同步 | 进程同步控制 |
信号 | 异步,简单 | 进程控制 |
Q5: 管道的读写特性?
- 当管道为空时,读操作阻塞
- 当管道满时,写操作阻塞
- 当写端关闭时,读操作返回0
- 当读端关闭时,写操作收到SIGPIPE信号
8.3 进程控制题
Q6: 什么是僵尸进程?如何避免?
- 子进程已终止但父进程未调用wait()回收资源
- 避免方法:调用wait()、处理SIGCHLD信号、使用SIGIGN忽略
Q7: 什么是孤儿进程?
- 父进程先于子进程终止
- 子进程被init进程收养
Q8: exec族函数的作用?
- 在当前进程中执行新程序
- 替换当前进程的内存映像
- 进程ID不变,但程序代码完全替换
8.4 高级应用题
Q9: 如何实现守护进程?
- fork()创建子进程,父进程退出
- 子进程调用setsid()创建新会话
- 再次fork(),避免获得控制终端
- 改变工作目录到根目录
- 重置文件权限掩码
- 关闭不需要的文件描述符
Q10: 多进程vs多线程如何选择?
- CPU密集型:多进程(避免GIL限制)
- I/O密集型:多线程(减少内存开销)
- 需要容错性:多进程(进程隔离)
- 需要共享状态:多线程(共享内存)
9. 实战编程题
9.1 生产者消费者模型
cpp
#include <sys/shm.h>
#include <sys/sem.h>
#include <iostream>
#define BUFFER_SIZE 10
struct shared_buffer {
int buffer[BUFFER_SIZE];
int in; // 生产者位置
int out; // 消费者位置
int count; // 当前元素数量
};
// 信号量操作函数
void sem_wait(int semid, int sem_num) {
struct sembuf sb = {sem_num, -1, 0};
semop(semid, &sb, 1);
}
void sem_signal(int semid, int sem_num) {
struct sembuf sb = {sem_num, 1, 0};
semop(semid, &sb, 1);
}
int main() {
key_t shm_key = ftok(".", 's');
key_t sem_key = ftok(".", 'e');
// 创建共享内存
int shmid = shmget(shm_key, sizeof(shared_buffer), IPC_CREAT | 0666);
shared_buffer* buffer = (shared_buffer*)shmat(shmid, NULL, 0);
// 初始化缓冲区
buffer->in = buffer->out = buffer->count = 0;
// 创建信号量集:0-mutex, 1-empty, 2-full
int semid = semget(sem_key, 3, IPC_CREAT | 0666);
semctl(semid, 0, SETVAL, 1); // mutex = 1
semctl(semid, 1, SETVAL, BUFFER_SIZE); // empty = BUFFER_SIZE
semctl(semid, 2, SETVAL, 0); // full = 0
if (fork() == 0) {
// 生产者进程
for (int i = 0; i < 20; i++) {
sem_wait(semid, 1); // wait(empty)
sem_wait(semid, 0); // wait(mutex)
// 生产
buffer->buffer[buffer->in] = i;
buffer->in = (buffer->in + 1) % BUFFER_SIZE;
buffer->count++;
printf("Produced: %d, count: %d\n", i, buffer->count);
sem_signal(semid, 0); // signal(mutex)
sem_signal(semid, 2); // signal(full)
usleep(100000); // 0.1秒
}
} else {
// 消费者进程
for (int i = 0; i < 20; i++) {
sem_wait(semid, 2); // wait(full)
sem_wait(semid, 0); // wait(mutex)
// 消费
int item = buffer->buffer[buffer->out];
buffer->out = (buffer->out + 1) % BUFFER_SIZE;
buffer->count--;
printf("Consumed: %d, count: %d\n", item, buffer->count);
sem_signal(semid, 0); // signal(mutex)
sem_signal(semid, 1); // signal(empty)
usleep(150000); // 0.15秒
}
wait(NULL);
// 清理资源
shmdt(buffer);
shmctl(shmid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID);
}
return 0;
}
9.2 简单的Shell实现
cpp
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>
class SimpleShell {
private:
std::vector<std::string> parse_command(const std::string& input) {
std::vector<std::string> tokens;
std::istringstream iss(input);
std::string token;
while (iss >> token) {
tokens.push_back(token);
}
return tokens;
}
char** vector_to_argv(const std::vector<std::string>& tokens) {
char** argv = new char*[tokens.size() + 1];
for (size_t i = 0; i < tokens.size(); i++) {
argv[i] = const_cast<char*>(tokens[i].c_str());
}
argv[tokens.size()] = nullptr;
return argv;
}
public:
void run() {
std::string input;
while (true) {
std::cout << "simple_shell> ";
std::getline(std::cin, input);
if (input.empty()) continue;
if (input == "exit") break;
// 内置命令
if (input.substr(0, 2) == "cd") {
handle_cd(input);
continue;
}
// 执行外部命令
execute_command(input);
}
}
private:
void handle_cd(const std::string& input) {
auto tokens = parse_command(input);
if (tokens.size() < 2) {
chdir(getenv("HOME"));
} else {
if (chdir(tokens[1].c_str()) != 0) {
perror("cd");
}
}
}
void execute_command(const std::string& input) {
auto tokens = parse_command(input);
if (tokens.empty()) return;
char** argv = vector_to_argv(tokens);
pid_t pid = fork();
if (pid == 0) {
// 子进程
if (execvp(argv[0], argv) == -1) {
perror("Command not found");
exit(1);
}
} else if (pid > 0) {
// 父进程
int status;
waitpid(pid, &status, 0);
} else {
perror("fork");
}
delete[] argv;
}
};
int main() {
SimpleShell shell;
shell.run();
return 0;
}
9.3 多进程排序
cpp
#include <algorithm>
#include <vector>
#include <sys/shm.h>
#define ARRAY_SIZE 1000
#define PROCESS_COUNT 4
struct shared_data {
int array[ARRAY_SIZE];
int sorted_parts[PROCESS_COUNT][ARRAY_SIZE / PROCESS_COUNT];
bool part_ready[PROCESS_COUNT];
};
void merge_arrays(int* result, int* arr1, int size1, int* arr2, int size2) {
int i = 0, j = 0, k = 0;
while (i < size1 && j < size2) {
if (arr1[i] <= arr2[j]) {
result[k++] = arr1[i++];
} else {
result[k++] = arr2[j++];
}
}
while (i < size1) result[k++] = arr1[i++];
while (j < size2) result[k++] = arr2[j++];
}
int main() {
// 创建共享内存
key_t key = ftok(".", 'a');
int shmid = shmget(key, sizeof(shared_data), IPC_CREAT | 0666);
shared_data* data = (shared_data*)shmat(shmid, NULL, 0);
// 初始化数组
srand(time(NULL));
for (int i = 0; i < ARRAY_SIZE; i++) {
data->array[i] = rand() % 1000;
}
// 初始化标志
for (int i = 0; i < PROCESS_COUNT; i++) {
data->part_ready[i] = false;
}
printf("Original array (first 20 elements): ");
for (int i = 0; i < 20; i++) {
printf("%d ", data->array[i]);
}
printf("\n");
// 创建子进程进行并行排序
for (int i = 0; i < PROCESS_COUNT; i++) {
if (fork() == 0) {
// 子进程:排序指定部分
int start = i * (ARRAY_SIZE / PROCESS_COUNT);
int end = (i + 1) * (ARRAY_SIZE / PROCESS_COUNT);
int size = end - start;
// 复制到本地数组进行排序
int local_array[size];
for (int j = 0; j < size; j++) {
local_array[j] = data->array[start + j];
}
// 排序
std::sort(local_array, local_array + size);
// 复制回共享内存
for (int j = 0; j < size; j++) {
data->sorted_parts[i][j] = local_array[j];
}
data->part_ready[i] = true;
printf("Process %d finished sorting\n", i);
exit(0);
}
}
// 等待所有子进程完成
for (int i = 0; i < PROCESS_COUNT; i++) {
wait(NULL);
}
// 合并排序结果
int part_size = ARRAY_SIZE / PROCESS_COUNT;
std::vector<int> result(ARRAY_SIZE);
// 简单的合并算法(可以优化为k路归并)
int* current_result = new int[ARRAY_SIZE];
int current_size = part_size;
// 复制第一部分
for (int i = 0; i < part_size; i++) {
current_result[i] = data->sorted_parts[0][i];
}
// 逐步合并其他部分
for (int i = 1; i < PROCESS_COUNT; i++) {
int* temp = new int[current_size + part_size];
merge_arrays(temp, current_result, current_size,
data->sorted_parts[i], part_size);
delete[] current_result;
current_result = temp;
current_size += part_size;
}
printf("Sorted array (first 20 elements): ");
for (int i = 0; i < 20; i++) {
printf("%d ", current_result[i]);
}
printf("\n");
// 验证排序结果
bool is_sorted = true;
for (int i = 1; i < ARRAY_SIZE; i++) {
if (current_result[i] < current_result[i-1]) {
is_sorted = false;
break;
}
}
printf("Array is %s\n", is_sorted ? "sorted correctly" : "NOT sorted");
// 清理资源
delete[] current_result;
shmdt(data);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
总结
C++进程编程涉及操作系统的核心概念,掌握这些知识点对于系统编程和面试都至关重要。重点要理解:
- 进程生命周期:创建、执行、终止的完整过程
- 进程间通信:各种IPC机制的特点和适用场景
- 进程同步:如何协调多个进程的执行
- 资源管理:避免资源泄漏和僵尸进程
- 实际应用:守护进程、进程池等高级技术
在面试中,不仅要掌握理论知识,还要能够编写实际的代码来解决问题。建议多做练习,理解每个系统调用的工作原理和使用场景。