poll()捕获线程返回值

时间:2017-01-25 11:38:02

标签: c++ c

我有一个带有小套接字通信的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,但是在我的最终代码中,命令需要更多的时间,所以我不能等到那个完成

1 个答案:

答案 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,则无需创建其他线程;只需执行以下步骤:

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