我有一个带有小套接字通信的poll()循环,我想通过system()或exec()启动另一个程序,我需要system()/ exec()的返回值,但我不知道我想在子进程运行时停止主循环,所以我想我是在一个线程中启动它但是我不知道如何设置pollfd以便在完成时捕获线程,我使用的是c / c ++ < / p>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <poll.h>
#include <iostream>
#include <string>
#include <thread>
#include <future>
#define SOCKET_NAME "/tmp/9Lq7BNBnBycd6nxy.socket"
int runProgram(const std::string &programName, const std::string &fileName) {
return system((programName + " " + fileName).c_str());
}
int main(int argc, char *argv[]) {
struct sockaddr_un server;
int sock;
char buf[1024];
unlink(SOCKET_NAME);
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1){
perror("socket");
exit(EXIT_FAILURE);
}
memset(&server, 0, sizeof(struct sockaddr_un));
server.sun_family = AF_UNIX;
strncpy(server.sun_path, SOCKET_NAME, sizeof(server.sun_path) - 1);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(sock, 3) < -1) {
perror("listen");
exit(EXIT_FAILURE);
}
struct pollfd fds[2];
fds[0].fd = sock;
fds[0].events = POLLIN;
std::future<int> ret = std::async(&runProgram, "cat", "test.txt");
while (true) {
poll(fds, 2, -1);
if(fds[0].revents & POLLIN) {
int new_sd = accept(fds[0].fd, NULL, NULL);
if (new_sd < 0) {
perror("accept");
}
fds[1].fd = new_sd;
}
if (fds[0].revents & POLLIN) {
int rv = recv(fds[1].fd, buf, 1024, 0);
if (rv < 0)
perror("recv");
else if (rv == 0) {
printf("disconnet\n");
close(fds[1].fd);
} else {
printf("%s\n", buf);
send(fds[1].fd, buf, 1024, 0);
}
memset(buf, 0, 1024);
}
}
close(sock);
return(EXIT_SUCCESS);
}
所以我想再添加一个到pollfd(fds [ret.get()])并在我的线程完成时获取fds [2]上的POLLIN并且我可以得到返回值(ret.get() ),在这里我使用了一个exaple命令cat,但是在我的最终代码中,命令需要更多的时间,所以我不能等到那个完成
答案 0 :(得分:0)
最简单的解决方案是创建一个匿名管道(或者,因为你说你在Linux上,eventfd)并在runProgram
函数中将数据写入管道的一端致电system
返回。然后,您可以在poll
的文件描述符集中包含管道的读取结束。
int process_eventfd = eventfd(0, EFD_CLOEXEC);
if (process_eventfd == -1) exit(1); // change this to handle appropriately
struct pollfd fds[3];
fds[0].fd = sock;
fds[0].events = POLLIN;
fds[1].fd = process_eventfd;
fds[1].events = POLLIN;
// use fds[2] instead of fds[1] for your socket connection, etc.
您可以将eventfd编号作为参数添加到runProgram
。它现在应该看起来像:
int runProgram(const std::string &programName, const std::string &fileName, int process_eventfd) {
return system((programName + " " + fileName).c_str());
uint64_t value = 1;
write(process_eventfd, &value, 8);
}
顺便说一下,你当前的程序有一个错误:你总是将2作为文件描述符的数量传递给poll
,甚至在你在数组中设置第二个文件描述符之前。您应该只传递数组中实际存在的有效描述符的数量。
但是,如果您不需要使用system
并且可以使用exec
,则无需创建其他线程;只需执行以下步骤:
fork
/ exec
ppoll
而不是poll
,并在要启用的信号中包含SIGCHLD ppoll
调用返回EINTR
错误,请使用waitpid
获取子状态子进程将与您的程序并行运行。