Skip to content

C++进程编程完整面试指南 ​

目录 ​

  1. 进程基础概念
  2. 进程创建与管理
  3. 进程继承机制
  4. 进程间通信(IPC)
  5. 进程同步与控制
  6. 进程状态与调度
  7. 高级进程编程
  8. 常见面试题汇总
  9. 实战编程题

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: 如何实现守护进程?

  1. fork()创建子进程,父进程退出
  2. 子进程调用setsid()创建新会话
  3. 再次fork(),避免获得控制终端
  4. 改变工作目录到根目录
  5. 重置文件权限掩码
  6. 关闭不需要的文件描述符

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++进程编程涉及操作系统的核心概念,掌握这些知识点对于系统编程和面试都至关重要。重点要理解:

  1. 进程生命周期:创建、执行、终止的完整过程
  2. 进程间通信:各种IPC机制的特点和适用场景
  3. 进程同步:如何协调多个进程的执行
  4. 资源管理:避免资源泄漏和僵尸进程
  5. 实际应用:守护进程、进程池等高级技术

在面试中,不仅要掌握理论知识,还要能够编写实际的代码来解决问题。建议多做练习,理解每个系统调用的工作原理和使用场景。