c++++多进程编程需借助系统接口实现。1.使用fork()创建子进程,通过getpid()获取pid并用wait()防止僵尸进程;2.进程间通信(ipc)包括管道、消息队列、共享内存配信号量等方法;3.共享内存需调用shmget/shmat映射和控制内存,并配合sem_open/sem_wait进行同步;4.避免死锁应遵循资源有序请求、预分配或超时机制,竞争条件可通过互斥锁、信号量解决;5.处理信号需用sigaction注册响应函数,kill发送信号,注意屏蔽及不可捕获信号特性。

C++本身并不直接支持多进程,需要借助操作系统提供的接口来实现。通常使用 fork() 创建子进程,并通过进程间通信(IPC)机制进行数据交换。

C++多进程编程,说白了就是利用操作系统提供的能力,让你的程序可以同时在多个“分身”里跑。这事儿听起来简单,但实际操作起来,坑还真不少。

最常用的方法是 fork()。fork() 会创建一个当前进程的几乎完全相同的副本,包括代码、数据、打开的文件等等。注意,fork() 调用会返回两次:一次在父进程中,返回子进程的进程ID;一次在子进程中,返回 0。这就是区分父子进程的关键。
立即学习“C++免费学习笔记(深入)”;
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// 子进程
std::cout << "子进程 (PID: " << getpid() << ") 正在运行" << std::endl;
// 执行子进程的任务
return 0;
} else if (pid > 0) {
// 父进程
std::cout << "父进程 (PID: " << getpid() << ") 创建了子进程 (PID: " << pid << ")" << std::endl;
wait(nullptr); // 等待子进程结束
std::cout << "子进程已结束" << std::endl;
} else {
// fork 失败
std::cerr << "fork() 失败" << std::endl;
return 1;
}
return 0;
}这段代码创建了一个简单的父子进程关系。父进程 wait(nullptr) 会等待子进程结束,防止出现僵尸进程。getpid() 函数获取当前进程的进程ID。unistd.h 和 sys/wait.h 是必要的头文件。wait(nullptr) 的使用是为了防止产生僵尸进程,这是多进程编程中需要特别注意的点。

进程间通信(IPC)是多进程编程的核心,因为不同的进程有各自独立的内存空间,不能直接访问彼此的数据。常见的 IPC 方法包括:
选择哪种 IPC 方法取决于你的具体需求。例如,如果只需要父子进程之间简单的数据传递,管道可能就足够了。如果需要多个进程频繁地共享数据,共享内存可能是更好的选择,但需要小心处理同步问题。
共享内存允许不同的进程访问同一块物理内存,从而实现快速的数据交换。但是,由于多个进程同时访问共享内存,需要使用同步机制(如信号量)来避免竞争条件。
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h> // For O_CREAT and O_EXCL
#include <unistd.h>
const int SHM_SIZE = 1024;
const char* SEM_NAME = "/my_semaphore";
int main() {
// 1. 获取共享内存
key_t key = ftok("shmfile", 65); // 创建一个key
int shmid = shmget(key, SHM_SIZE, 0666 | IPC_CREAT);
if (shmid == -1) {
perror("shmget");
return 1;
}
// 2. 映射共享内存到进程地址空间
char* shm = (char*)shmat(shmid, nullptr, 0);
if (shm == (char*) -1) {
perror("shmat");
return 1;
}
// 3. 创建或打开信号量
sem_t* sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0666, 1); // 初始化为1
if (sem == SEM_FAILED) {
if (errno == EEXIST) {
sem = sem_open(SEM_NAME, 0); // 如果信号量已存在,则打开
} else {
perror("sem_open");
shmdt(shm);
shmctl(shmid, IPC_RMID, nullptr);
return 1;
}
}
pid_t pid = fork();
if (pid == 0) {
// 子进程
sem_wait(sem); // 获取信号量,进入临界区
std::cout << "子进程读取到的数据: " << shm << std::endl;
sem_post(sem); // 释放信号量,退出临界区
shmdt(shm);
sem_close(sem);
return 0;
} else if (pid > 0) {
// 父进程
sem_wait(sem); // 获取信号量,进入临界区
sprintf(shm, "Hello from parent process!");
sem_post(sem); // 释放信号量,退出临界区
wait(nullptr);
shmdt(shm);
shmctl(shmid, IPC_RMID, nullptr); // 删除共享内存
sem_close(sem);
sem_unlink(SEM_NAME); // 删除信号量
} else {
perror("fork");
shmdt(shm);
shmctl(shmid, IPC_RMID, nullptr);
sem_close(sem);
sem_unlink(SEM_NAME);
return 1;
}
return 0;
}这个例子展示了如何使用共享内存和信号量进行进程间通信。shmget() 用于获取共享内存,shmat() 用于将共享内存映射到进程的地址空间,shmdt() 用于解除映射,shmctl() 用于控制共享内存(例如,删除)。sem_open() 用于创建或打开信号量,sem_wait() 用于获取信号量,sem_post() 用于释放信号量,sem_close() 用于关闭信号量,sem_unlink() 用于删除信号量。
注意:信号量使用命名信号量,需要在程序结束时使用 sem_unlink() 删除,否则下次运行程序可能会出错。共享内存也需要在程序结束时使用 shmctl(shmid, IPC_RMID, nullptr) 删除,否则会一直存在于系统中。
死锁和竞争条件是多进程编程中常见的并发问题。
避免死锁的常见方法包括:
避免竞争条件的常见方法包括:
选择合适的同步机制,并仔细设计程序的逻辑,是避免死锁和竞争条件的关键。
信号是操作系统向进程发送的通知,用于处理各种事件,例如用户中断 (Ctrl+C)、定时器到期、进程终止等等。在多进程编程中,需要特别注意信号的处理,因为信号可能会被发送到错误的进程,或者导致程序的意外行为。
通常,父进程需要设置信号处理函数,并使用 sigaction() 函数来注册信号处理程序。子进程会继承父进程的信号处理设置,但也可能需要根据自己的需要进行修改。
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
void signal_handler(int signum) {
std::cout << "接收到信号: " << signum << std::endl;
// 处理信号
}
int main() {
struct sigaction sa;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGINT, &sa, nullptr); // 注册 SIGINT 信号处理程序
pid_t pid = fork();
if (pid == 0) {
// 子进程
while (true) {
std::cout << "子进程正在运行..." << std::endl;
sleep(1);
}
return 0;
} else if (pid > 0) {
// 父进程
std::cout << "父进程正在运行..." << std::endl;
sleep(5);
kill(pid, SIGINT); // 向子进程发送 SIGINT 信号
wait(nullptr);
std::cout << "子进程已结束" << std::endl;
} else {
perror("fork");
return 1;
}
return 0;
}在这个例子中,父进程注册了 SIGINT 信号的处理程序,并在 5 秒后向子进程发送 SIGINT 信号。子进程接收到信号后,会执行 signal_handler() 函数。kill() 函数用于向指定的进程发送信号。
需要注意的是,某些信号(例如 SIGKILL)不能被捕获或忽略。此外,在多线程程序中,信号的处理更加复杂,需要使用 pthread_sigmask() 函数来控制线程的信号屏蔽。
总而言之,C++ 多进程编程需要深入理解操作系统的相关概念,并小心处理并发问题。希望这些例子能帮你更好地理解 C++ 多进程编程。
以上就是C++怎么使用多进程 C++多进程编程的基本方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号