2017-01-25 8 views
-1

私は小さなソケット通信でpoll()ループを持っています。system()またはexec()で他のプログラムを開始したいのですが、システムの戻り値が必要です/ exec()しかし、子プロセスが実行されている間にメインループを止めたくないので、スレッドで開始すると思ったが、完了したらスレッドを捕まえるためにpollfdを設定する方法がわからない。私は、だから私はたpollfd(FDS [ret.get()])への1以上を追加して、私のスレッドが実行されたときに、[2] FDSにPOLLINを取得したいと私ができるC/C++poll()catchスレッドの戻り値

#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); 
} 

を使用しています戻り値を取得する(ret.get())、ここで私はexapleコマンドcatを使用しましたが、最終的なコードではコマンドがより多くの時間を必要とするので、終了するのを待ちません。

+2

コードも含めてください。 –

+0

あなたはどのプラットフォームを使用していますか? – UKMonkey

+0

linux g ++、私はちょうどコードを追加しました(これはオリジナルの抽出された最小化されたバージョンです) – Sekkmer

答えて

0

最も簡単な解決策は、systemへの呼び出しが返されたあと、runProgram関数のパイプの一端にデータを書き込んで、匿名パイプ(または、あなたがLinux上にあると言うので、eventfd)を作成することです。 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. 

runProgramに引数としてeventfd番号を追加できます。それは、今のようなものになります。ちなみに

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); 
} 

を、あなたの現在のプログラムにはバグがあります:あなたは常にあなたが第二のファイル記述子を設定している前であっても、pollにファイル記述子の数として2を渡しますアレイ。配列に実際に存在する有効な記述子の数だけ渡す必要があります。

ただし、systemを使用する必要がなく、execを使用できる場合は、別のスレッドを作成する必要はありません。ただ、次の手順を実行します。

  1. マスク(しかしを無視しないでください)SIGCHLDシグナル。 (何もしなくても、シグナルハンドラを設定する必要があるかもしれません;これがLinuxに当てはまるかどうかは覚えていません)。
  2. fork/exec
  3. 使用ppollではなく、poll経由で外部プロセスを作成し、ppoll呼び出しがEINTRエラーを返した場合
  4. 、子のステータスを取得するためにwaitpidを使用有効にする信号でSIGCHLDを含める

子プロセスは、プログラムと並行して実行されます。