一、进程介绍
进程是指在操作系统中正在运行的一个程序,它在操作系统中占有一定的资源,如内存、I/O、CPU时间等。
每个进程都有自己的地址空间,互相之间无法访问,是通过操作系统提供的IPC(进程间通信)机制来进行进程间的通信和数据交互。
在C++中,可以通过一些库函数来创建和控制进程的运行,如fork()、exec()、wait()等函数。
二、多进程编程
多进程编程是指同时运行多个进程,它可以提高程序的并发性和效率,对于系统性能和响应时间的要求高时非常有用。
在C++中,创建一个新进程可以使用fork()函数,它会复制父进程的所有资源,包括代码、数据、栈、堆等,然后子进程继续执行fork()函数后的语句,而父进程则返回子进程的进程ID,这样父子进程可以在不同的代码分支中执行不同的任务。
可以通过判断fork()函数的返回值来确定当前代码执行的是父进程还是子进程:
pid_t pid = fork(); if (pid == 0) { // 子进程 } else if (pid > 0) { // 父进程 } else { // 出错处理 }
其中pid_t是一个整型类型,代表进程ID,如果pid等于0,则表示当前代码执行的是子进程的分支;如果pid大于0,则表示当前代码执行的是父进程的分支,pid就是子进程的进程ID;如果pid小于0,则表示创建新进程失败。
除了fork()函数,还可以使用exec系列函数和wait()函数来控制进程的运行。
三、进程间通信
进程间通信(IPC)是指两个或多个进程之间的数据交换和通信,可以使用多种方式进行进程间通信,常见的有管道、消息队列、共享内存和信号量等。
其中,管道是最简单的通信方式,它可以在两个进程之间传递字符流,但只能用于具有亲缘关系的进程之间通信(即通过fork()函数创建的父子进程);消息队列可以传递复杂的数据结构,但如果数据量比较大时会影响性能;共享内存可以实现多个进程之间对同一块内存的访问,但需要解决进程同步和互斥的问题;信号量可以用来实现进程之间的同步和互斥,但需要掌握一定的信号量编程技巧。
下面是一个使用管道在父子进程之间传递数据的例子:
const int BUFFER_SIZE = 1024; int pipe_fd[2]; char message[BUFFER_SIZE]; pid_t pid; if (pipe(pipe_fd) < 0) { std::cerr << "create pipe error." << std::endl; exit(-1); } if ((pid = fork()) == -1) { std::cerr << "fork error." << std::endl; exit(-1); } else if (pid == 0) { close(pipe_fd[1]); // 关闭写通道 if (read(pipe_fd[0], message, BUFFER_SIZE) == -1) { std::cerr << "read error." << std::endl; exit(-1); } std::cout << "child process received message: " << message << std::endl; close(pipe_fd[0]); // 关闭读通道 } else { close(pipe_fd[0]); // 关闭读通道 std::string input_message; std::cout << "input message to be sent to child process: "; std::getline(std::cin, input_message); if (write(pipe_fd[1], input_message.c_str(), input_message.size()) == -1) { std::cerr << "write error." << std::endl; exit(-1); } close(pipe_fd[1]); // 关闭写通道 wait(NULL); // 等待子进程结束 }
四、进程管理
进程管理是指对操作系统中的进程进行管理和调度,包括创建进程、终止进程、监控进程等操作,常用的进程管理工具有ps、top和kill等。
在C++中,可以使用系统函数kill()来终止一个进程,需要传入进程ID和终止信号:
if (kill(pid, SIGKILL) == -1) { std::cerr << "kill process error." << std::endl; exit(-1); }
其中,SIGKILL是一个宏定义,代表终止信号。
五、多进程编程实例
下面是一个简单的多进程ping程序,它可以并行的ping多个IP地址,同时显示结果:
#include #include #include #include #include #include #include #include #include #include #include const int MAX_PROC_NUM = 10; const int MAX_IP_NUM = 10; const int MAX_RESULT_SIZE = 1024; int proc_num = 0; char ip_list[MAX_IP_NUM][16]; bool ping(const char* ip) { char cmd[1024] = {0}; sprintf(cmd, "ping -c 4 %s", ip); FILE* pipe = popen(cmd, "r"); if (!pipe) { return false; } char buffer[MAX_RESULT_SIZE]; memset(buffer, 0, MAX_RESULT_SIZE); while (!feof(pipe)) { if (fgets(buffer, MAX_RESULT_SIZE, pipe)) { std::cout << buffer; } } if (pclose(pipe) == -1) { return false; } return true; } void handle_signal(int signo) { std::cout << "process " << getpid() << " received signal " << signo << std::endl; exit(signo); } void start_proc(int idx) { const char* ip = ip_list[idx]; std::cout << "start ping " << ip << ", process id " << getpid() << std::endl; if (signal(SIGINT, handle_signal) == SIG_ERR) { std::cerr << "error setting signal handler." << std::endl; exit(-1); } ping(ip); std::cout << "ping " << ip << " finish, process id " << getpid() < 0) { std::cout << "process " << pid << " exit with status " << WEXITSTATUS(status) << std::endl; proc_num--; } } int main(int argc, char* argv[]) { if (argc < 2) { std::cerr << "usage: " << argv[0] << " ip1 [ip2] [...]" < MAX_IP_NUM) { std::cerr << "too many ip addresses." << std::endl; return -1; } for (int i = 0; i < argc - 1; ++i) { strncpy(ip_list[i], argv[i + 1], sizeof(ip_list[i])); } for (int i = 0; i 0) { // parent } else { std::cerr << "fork process error." < 0) { check_procs(); sleep(1); } return 0; }
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/235615.html