看来有些人对boost有偏见啊
自己用fork/select手撸一个,需要一段时间才能稳定
[code]
请使用Linux OS提供的API实现如下一个C++程序:
创建子进程,并通过管道将一个输入队列中的每个消息写入到子进程的标准输入,并通过管道从子进程的标准输出读取出每个处理结果的消息。
每个输入消息允许子进程耗费5秒去处理。
要求使用非阻塞方式进行管道通信,便于取消管道操作。
"等待子进程退出"这个操作,也改为异步的或者非阻塞的模式。
下面是一个使用 Linux OS API 的 C++ 程序,实现了创建子进程、通过管道进行输入输出、非阻塞方式进行管道通信、以及异步或非阻塞模式等功能。该程序通过以下步骤实现:
创建两个管道,分别用于将数据从父进程传递到子进程,和将数据从子进程传递回父进程。
创建子进程,并将其输入和输出连接到相应的管道中。
父进程从输入队列中读取消息,并将其写入到子进程的标准输入管道中。如果写入操作被阻塞,程序将等待一定时间后重新尝试写入。
父进程从子进程的标准输出管道中读取处理结果的消息。如果读取操作被阻塞,程序将等待一定时间后重新尝试读取。
异步或非阻塞等待子进程退出,并在子进程退出后关闭管道。
下面是实现该功能的代码:
c++
Copy code
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
using namespace std;
const int kBufferSize = 1024;
const int kMaxRetryTimes = 10;
const int kMaxWaitTimeMs = 100;
// 从输入队列中读取消息
bool readFromQueue(int &msg) {
// TODO: 从输入队列中读取消息
return true;
}
// 将消息写入子进程的标准输入
bool writeToChild(int childStdin, int msg) {
char buffer[kBufferSize];
int n = snprintf(buffer, kBufferSize, "%d\n", msg);
int written = 0;
int retryTimes = 0;
while (written < n && retryTimes < kMaxRetryTimes) {
int ret = write(childStdin, buffer + written, n - written);
if (ret < 0) {
if (errno == EAGAIN) {
usleep(kMaxWaitTimeMs * 1000);
retryTimes++;
continue;
}
return false;
}
written += ret;
}
return written == n;
}
// 从子进程的标准输出中读取处理结果
bool readFromChild(int childStdout, int &result) {
char buffer[kBufferSize];
int readed = 0;
int retryTimes = 0;
while (retryTimes < kMaxRetryTimes) {
int ret = read(childStdout, buffer + readed, kBufferSize - readed);
if (ret < 0) {
if (errno == EAGAIN) {
usleep(kMaxWaitTimeMs * 1000);
retryTimes++;
continue;
}
return false;
} else if (ret == 0) {
// 子进程已退出
break;
}
readed += ret;
}
if (readed > 0) {
result = atoi(buffer);
return true;
}
return false;
}
// 等待子进程退出
void waitForChild(pid_t childPid, bool async) {
bugtraq@163.com
继续
如果要异步或非阻塞等待子进程退出,可以使用 Linux 的信号机制。具体地,可以使用 SIGCHLD 信号来通知父进程子进程已经退出。父进程可以将 SIGCHLD 信号的处理函数设置为非阻塞模式,即不等待子进程退出,而是在信号处理函数中调用 waitpid() 函数来等待子进程退出,并释放子进程的资源。
下面是修改后的代码:
c++
Copy code
// 处理 SIGCHLD 信号的处理函数
void handleChildExit(int signal) {
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
if (pid > 0) {
cout << "Child process " << pid << " exited with status " << status << endl;
}
}
int main() {
// 创建管道
int toChild[2], toParent[2];
if (pipe(toChild) < 0 || pipe(toParent) < 0) {
perror("Failed to create pipe");
return -1;
}
// 创建子进程
pid_t childPid = fork();
if (childPid < 0) {
perror("Failed to create child process");
return -1;
} else if (childPid == 0) {
// 子进程
close(toChild[1]);
close(toParent[0]);
dup2(toChild[0], STDIN_FILENO);
dup2(toParent[1], STDOUT_FILENO);
execl("/bin/cat", "cat", NULL);
perror("Failed to exec child process");
exit(-1);
} else {
// 父进程
close(toChild[0]);
close(toParent[1]);
// 将 SIGCHLD 信号处理函数设置为非阻塞模式
struct sigaction sa;
sa.sa_handler = handleChildExit;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &sa, NULL) < 0) {
perror("Failed to set SIGCHLD handler");
return -1;
}
int msg;
int result;
while (readFromQueue(msg)) {
if (!writeToChild(toChild[1], msg)) {
cerr << "Failed to write to child process" << endl;
break;
}
cout << "Sent message " << msg << " to child process" << endl;
if (readFromChild(toParent[0], result)) {
cout << "Received result " << result << " from child process" << endl;
} else {
cerr << "Failed to read from child process" << endl;
break;
}
}
close(toChild[1]);
// 父进程在等待子进程退出时可以不阻塞,可以异步或非阻塞等待子进程退出
if (!async) {
int status;
if (waitpid(childPid, &status, 0) < 0) {
perror("Failed to wait for child process");
}
}
close(toParent[0]);
}
return 0;
}
在上面的代码中,SIGCHLD 信号处理函数 handleChildExit() 中使用 waitpid()
bugtraq@163.com
上面的消息读写没有5秒超时,请加上
要在消息读写中添加超时功能,可以使用 Linux 的 select() 函数来实现非阻塞的 I/O 操作。具体地,可以使用 select() 函数来等待管道读写操作的完成,并设置一个超时时间。如果管道读写操作在超时时间内未完成,则 select() 函数会返回,可以在这个时候中断管道操作,并继续下一个操作。
下面是添加了超时功能的代码:
c++
Copy code
#include <sys/select.h>
#include <sys/time.h>
int main() {
// 创建管道
int toChild[2], toParent[2];
if (pipe(toChild) < 0 || pipe(toParent) < 0) {
perror("Failed to create pipe");
return -1;
}
// 创建子进程
pid_t childPid = fork();
if (childPid < 0) {
perror("Failed to create child process");
return -1;
} else if (childPid == 0) {
// 子进程
close(toChild[1]);
close(toParent[0]);
dup2(toChild[0], STDIN_FILENO);
dup2(toParent[1], STDOUT_FILENO);
execl("/bin/cat", "cat", NULL);
perror("Failed to exec child process");
exit(-1);
} else {
// 父进程
close(toChild[0]);
close(toParent[1]);
// 将 SIGCHLD 信号处理函数设置为非阻塞模式
struct sigaction sa;
sa.sa_handler = handleChildExit;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &sa, NULL) < 0) {
perror("Failed to set SIGCHLD handler");
return -1;
}
int msg;
int result;
while (readFromQueue(msg)) {
if (!writeToChild(toChild[1], msg)) {
cerr << "Failed to write to child process" << endl;
break;
}
cout << "Sent message " << msg << " to child process" << endl;
// 等待子进程的处理结果
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(toParent[0], &readSet);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int selectResult = select(toParent[0] + 1, &readSet, NULL, NULL, &timeout);
if (selectResult == 0) {
cerr << "Timed out waiting for result from child process" << endl;
continue;
} else if (selectResult < 0) {
perror("Failed to wait for result from child process");
break;
}
if (readFromChild(toParent[0], result)) {
cout << "Received result " << result << " from child process" << endl;
} else {
cerr << "Failed to read from child process" << endl;
break;
}
}
close(toChild[1]);
// 父进程在等待子进程退出时可以不阻塞,可以异步或非阻塞等待子进程退出
if (!async) {
int status;
if (waitpid(childPid
bugtraq@163.com
继续
(childPid, &status, 0) < 0) {
perror("Failed to wait for child process to exit");
return -1;
}
if (WIFEXITED(status)) {
cout << "Child process exited with status " << WEXITSTATUS(status) << endl;
} else if (WIFSIGNALED(status)) {
cout << "Child process exited due to signal " << WTERMSIG(status) << endl;
}
} else {
int status;
pid_t result = waitpid(childPid, &status, WNOHANG);
while (result == 0) {
// 等待子进程退出
sleep(1);
result = waitpid(childPid, &status, WNOHANG);
}
if (result < 0) {
perror("Failed to wait for child process to exit");
return -1;
}
if (WIFEXITED(status)) {
cout << "Child process exited with status " << WEXITSTATUS(status) << endl;
} else if (WIFSIGNALED(status)) {
cout << "Child process exited due to signal " << WTERMSIG(status) << endl;
}
}
}
kotlin
Copy code
return 0;
}
scss
Copy code
在这个代码中,我们使用 select() 函数来等待管道读写操作的完成,并设置一个超时时间。如果管道读写操作在超时时间内未完成,则 select() 函数会返回,程序会打印出一条超时错误信息,并继续下一个操作。
另外,在等待子进程退出的操作中,我们可以使用异步或非阻塞的方式等待子进程退出。如果使用异步方式等待子进程退出,父进程将定期调用 waitpid() 函数来检查子进程是否已退出。如果使用非阻塞方式等待子进程退出,父进程可以使用 WNOHANG 选项来调用 waitpid() 函数,这样父进程不会阻塞在等待子进程退出的操作上。
[/code]
【 在 Madlee 的大作中提到: 】
: 竟然用boost,差评。要他不用boost试试
--
修改:z16166 FROM 114.241.225.*
FROM 114.241.225.*