c++ - poll() 捕获线程返回值

标签 c++ c

我有一个带有小型套接字通信的 poll() 循环,我想通过 system() 或 exec() 启动另一个程序,并且我需要 system()/exec() 的返回值,但我不知道不想在子进程运行时停止主循环,所以我想我在线程中启动它,但我不确定如何设置 pollfd 以在线程完成时捕获线程,我正在使用 c/c++

#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() ),这里我使用了一个示例命令 cat,但在我的最终代码中,该命令需要更多时间,所以我等不及完成

最佳答案

最简单的解决方案是创建一个匿名管道(或者,因为您说您在 Linux 上,所以是 eventfd )并将数据写入 runProgram 中管道的一端。一旦调用 system 即可函数返回。然后,您可以将管道的读取端包含在您的文件描述符集中 poll ing。

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 ,不需要再创建一个线程;只需执行以下步骤:

  1. 屏蔽(但不要忽略)SIGCHLD 信号。 (您可能需要设置一个信号处理程序,即使它什么也不做;我不记得这对于 Linux 是否适用)。
  2. 通过 fork 创建您的外部流程/exec
  3. 使用ppoll而不是poll ,并在要启用的信号中包含 SIGCHLD
  4. 如果 ppoll调用返回 EINTR错误,使用waitpid获取 child 身份

子进程将与您的程序并行运行。

关于c++ - poll() 捕获线程返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41850655/

相关文章:

c - 如何解决 'right-hand operand has no effect'错误?

c - 在C中随机选择两个数字(掷硬币)的快速方法

c++ - 本地范围内子命名空间的命名空间别名

clang-format 导致编译的目标文件发生更改

c++ - 按下空间时如何获得更平滑的旋转

c++ - 向 Code::Blocks 添加链接器选项

将 NSData 复制到 UnsafeMutablePointer<Void>

C 程序使用函数查找两个数字之间的最大值和最小值

c++ - 列号 1 超出范围 0..-1

c++ - 固定大小的特征类型作为参数