天道酬勤,学无止境

C Read from pipe blocks until child is terminated

Parent process creates N children each one replaces itself with exec. There is a communication between parent and exec through an array of pipes (int pipefd[N][2];)

The exec writes to the pipe with these commands:

char msg[50];
sprintf( msg, "\tsent from pid: %d, pi= %f", getpid(), pi);
printf("%s\n",msg);
write(i1, msg, strlen(msg)+1);

and the parent reads with these:

for (i=0;i<N;i++) {
   close(pipefd[i][1]);  // close the write end of the pipe in the parent

   read(pipefd[i][0], buffer, sizeof(buffer));
   printf("\n-C-\n");

   if (buffer[0] == '\t'){
     printf("%s\n",buffer);
   }
   int j;
   for (j=0; j<100; j++) {
      buffer[j]='\n';
   }
   close(pipefd[i][0]);
}

Now the problem is that only after the child is terminated the read gets unblocked and prints the buffer. What I want to do is print the buffer immediately after the exec writes to the pipe.

Below is the all the code:

Parent File:

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>

#define N 5
pid_t *pid;
int pipefd[N][2];

int flag = 0;
int count_ctrl_c = 0;
void signal_handler(int sig){
    signal(sig, SIG_IGN);
    printf("\n");

    flag = 1;
    signal(SIGINT, signal_handler);
}

int main(int argc, char *argv[]) {


    int i;
    for (i = 0; i < N; i++) {
        pipe(pipefd[i]);
    }

    int parent_pid = getpid();
    pid= (pid_t *)malloc(N * sizeof(pid_t));

    for (i = 0; i < N; i++) {
        pid[i] = fork();
        if (pid[i] == 0) //The parent process will keep looping
        {

            char b[50];
            sprintf( b, "%d", i+1);

            char i0[50];
            sprintf( i0, "%d", pipefd[i][0]);

            char i1[50];
            sprintf( i1, "%d", pipefd[i][1]);

            char par_id[50];
            sprintf( par_id, "%d", parent_pid);

            execl("***the/path/to/exec/calculate***", b,i0,i1,par_id,NULL);
        }
    }

    if (parent_pid == getpid()) {
        signal(SIGINT, signal_handler);


        while(1){
            if (flag){

                printf("\n-A-\n");
                char buffer[100];
                int i;
                for (i=0;i<N;i++) {
                    // Apostellei to shma SIGUSR2 se ola ta paidia tou
                    kill(pid[i], SIGUSR2);
                }

                printf("\n-B-\n");
                for (i=0;i<N;i++) {
                    close(pipefd[i][1]);  // close the write end of the pipe in the parent

                    read(pipefd[i][0], buffer, sizeof(buffer));
                    printf("\n-C-\n");
                    if (buffer[0] == '\t'){
                        printf("%s\n",buffer);
                    }
                    int j;
                    for (j=0; j<100; j++) {
                        buffer[j]='\n';
                    }
                    close(pipefd[i][0]);
                }
                //exit(0);
                printf("finished reading\n");

                flag = 0;
                count_ctrl_c++;
                if (count_ctrl_c == 2) {
                    exit(0);
                }
            }

        }
    }
}

calculate.c

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>

#define N 5

int i0,i1,parent_pid;

int flag = 0;
int time_to_term = 0;
double pi;

void signal_handler2(int sig);
void signal_handler(int sig);

void signal_handler2(int sig){
    signal(sig, SIG_IGN);
    signal(SIGALRM, SIG_IGN);
    flag = 1;
    signal(SIGUSR2, signal_handler2);
    signal(SIGALRM, signal_handler);
}

void signal_handler(int sig){
    signal(sig, SIG_IGN);
    pid_t pid = getpid();
    printf("time: %d, pid: %d, pi: %1.10f\n", time_to_term, pid, pi);
    exit(0);
}

int main(int argc, char *argv[]) {
    int pid;
    signal(SIGINT, SIG_IGN);
    signal(SIGUSR2, signal_handler2);
    signal(SIGALRM, signal_handler);

    time_to_term = atoi(argv[0]);   
    alarm(time_to_term);

    i0 = atoi(argv[1]);
    i1 = atoi(argv[2]);
    parent_pid = atoi(argv[3]);

    double mul = 1.0;
    double par = 2.0;
    pi = 3.0;

    while(1){


        pi = pi + (mul * (4.0 / (par * (par + 1.0) * (par + 2.0))));
        mul = mul * (-1.0);
        par += 2;

        sleep(1);

         if (flag) {
            signal(SIGALRM, SIG_IGN);
            close(i0);

            char msg[50];
            sprintf( msg, "\tsent from pid: %d, pi= %f", getpid(), pi);
             printf("%s\n",msg);
            write(i1, msg, strlen(msg)+1);

            close(i1);
            flag = 0;

            signal(SIGALRM, signal_handler);
            //exit(0);


        }
    }

}
标签

评论

General tip for troubleshooting this: Run both sides of the pipeline using the strace tool (you can use strace -f to follow forks) so that you can verify what is actually written / read from the pipe.

I suspect that in this case, nothing is written by the child! This is because the stdio layer that you use (printf()) checks whether it is writing to a terminal or to, well, anything else. In case of terminal, it flushes the output after each newline, but in other cases, it flushes only after a large-ish block of data is written (8KiB on GNU systems). Try flushing the output manually using fflush() after printf(). If that helps, you can adjust stdout buffering mode using setvbuf().

IMHO, your design is not really good as all child processes inherit all pipes you created and this is a waste of system resources. The right thing to do would be:

In the parent process:

  1. dup fd's #0 and #1 to preserve for later use by the parent process; use fcntl with F_DUPFD_CLOEXEC on these new fd's to prevent inheritance on exec

  2. close fd #0

  3. close fd #1

  4. create a pipe

  5. prevent inheritance of the read fd of the pipe as said above

  6. dup2 write fd of the pipe to make it fd #1; close the original write fd

  7. fork & exec the child process

  8. repeat steps 3 through 7 for all necessary children

  9. dup2 stored duplicates of original fd's #0 and #1 back to #0 and #1 to restore the printf/scaf functionality

  10. use select to poll read fd's of all pipes and possibly #0 if you expect any input on #0

If two-way communication is required then at step 4 create two pipes with appropriate adjustments to the described procedure and repeat steps 2 through 7 to create children.

In the child process (after exec)

Do all processing as required. Write to the parent either using fd #1 or printf or whatever. Child process may always obtain its parent PID with getppid()

Your operating system is probably buffering the write.

Try using ioctl and FLUSHW to explicitly flush the pipe after the call to write. Also, check your return values in case something insidious is happening. See http://pubs.opengroup.org/onlinepubs/7908799/xsh/ioctl.html for more reading on ioctl.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 使用proc_open时从STDIN管道读取(Reading from STDIN pipe when using proc_open)
    问题 我正在尝试建立一个网站,使人们可以在线编译和运行他们的代码,因此我们需要找到一种交互式的方式来使用户发送指令。 实际上,首先想到的是exec()或system() ,但是当用户想要输入某物时,这种方式将行不通。 因此,我们必须使用proc_open() 。 例如,以下代码 int main() { int a; printf("please input a integer\n"); scanf("%d", &a); printf("Hello World %d!\n", a); return 0; } 当我使用proc_open() ,像这样 $descriptorspec = array( 0 => array( 'pipe' , 'r' ) , 1 => array( 'pipe' , 'w' ) , 2 => array( 'file' , 'errors' , 'w' ) ); $run_string = "cd ".$addr_base."; ./a.out 2>&1"; $process = proc_open($run_string, $descriptorspec, $pipes); if (is_resource($process)) { //echo fgets($pipes[1])."<br/>"; fwrite($pipes[0], '12')
  • 为什么父进程的输出被子进程阻塞?(Why is output of parent process blocked by child process?)
    问题 在下面的代码中,我将我的进程分叉为父进程和子进程。 在子进程中,我将c字符串argv[1]发送给父进程进行打印。 然后我让子进程休眠 4 秒,然后打印“这是子进程。关闭\n”。 在父进程中,我希望子进程中的字符串在我从子进程收到后立即打印到标准输出。 问题出现在这里。 在 4 秒后打印字符串“这是子进程。关闭\n”之前,而不是在父进程中立即打印 argv[1],而是这样: $ g++ -std=c++11 printchild.cpp -o printchild $ ./printchild helloworld 1) 4 秒过去 2)打印“这是子进程。关闭\n” 3)打印“helloworld” 为什么父进程的输出被子进程阻塞? // printchild.cpp #include <chrono> #include <thread> #include <cstdio> #include <unistd.h> #include <cstdlib> int main(int argc, char * argv[]){ int pipefd[2]; pid_t cpid; if(argc != 2){ fprintf(stderr, "Usage: %s <string>\n", argv[0]); exit(EXIT_FAILURE); } if(pipe(pipefd) =
  • 在孩子退出之前无法从流中读取?(can't read from stream until child exits?)
    问题 好的,我有一个程序可以创建两个管道 -> 分叉 -> 孩子的 stdin 和 stdout 被重定向到每个管道的一端 -> 父级连接到管道的另一端并尝试读取与子级关联的流输出并将其打印到屏幕上(我最终也会让它写入孩子的输入)。 问题是,当父级尝试 fgets 子级的输出流时,它只是停止并等待子级死到 fgets 然后打印输出。 如果孩子不退出,它只是永远等待。 到底是怎么回事? 我认为 fgets 可能会阻塞,直到流中出现某些东西,但不会一直阻塞,直到孩子放弃其文件描述符。 这是代码: #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char *argv[]) { FILE* fpin; FILE* fpout; int input_fd[2]; int output_fd[2]; pid_t pid; int status; char input[100]; char output[100]; char *args[] = {"/somepath/someprogram", NULL}; fgets(input, 100, stdin); // the user inputs the
  • 如何等待php中proc_open()执行的进程?(How to wait for a process executed by proc_open() in php?)
    问题 请阅读此问题后,不要说它已被复制。我已经在网上搜索过,但是没有一种解决方案适合我。 我在做什么:-> 我正在本地主机上运行apache服务器,通过php获取源文件(例如.c)。我将该文件保存在“ / code /”目录中,并在php中使用proc_open()编译并执行此源文件。现在我想要等待主要的php脚本,直到“ proc_open()”创建的进程终止,所以我使用了“ pcntl_waitpid()”。但是我认为使用“ pcntl_waitpid()”存在问题,因为“ pcntl_waitpid()”之后的脚本没有执行。 由“ pcntl_waitpid()”创建的进程从“ /code/input.txt”文件获取输入,并将输出提供给“ /code/output.txt”文件,因此出于重定向目的,我使用proc_open(),这样我可以轻松实现重定向流。 我的机器配置: 操作系统-> Ubuntu 12.04 LT PHP 5.3.10 APACHE 2.2.22 在本地主机上运行 权限:- /代码-> 777 主php文件所在的文件夹-> 777(由于安全原因,我知道777不好,但是由于我在本地服务器上运行脚本,因此这些权限没有问题。) 我想要什么:-任何人都可以告诉我什么方式,以便我可以停止主要的php脚本,直到proc-open()创建的进程终止
  • 子进程完成写入FIFO后,父进程如何读取FIFO?(How does a parent process read a FIFO after the child process finished the writing that FIFO?)
    问题 我有一个非常简单的基本程序,它有两个进程,第一个是parent ,第二个是child 。 子进程应该向FIFO写一些东西。 在所有写入作业完成后(子进程终止后)。 然后父进程应该读取所​​有FIFO文件并打印到stdout 。 所以我想,我需要一个wait(NULL); 为parent 。 所以parent会等到child被终止。 但是child也因为写入而被阻塞,并且因为读取这个写入而被阻塞。 所以两个进程都互相等待,我认为,发生了死锁。 我的程序是这样的: #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <string.h> #include <sys/file.h> int writeSomeStuffToFifo (); void printAllFifo (); char * myfifo = "myfifo"; int main(int argc, char **argv) { int pid=0; int childPid=-1; int status; pid=fork(); if ((pid = fork()) < 0){ perror(
  • fclose()/ pclose()可能在某些文件指针上阻塞(fclose()/pclose() may block on some file pointers)
    问题 在dup()对其文件描述符块进行调用之后,在此处调用fclose() ,直到子进程结束(大概是因为流已经结束)。 FILE *f = popen("./output", "r"); int d = dup(fileno(f)); fclose(f); 但是,通过手动执行popen()的pipe() , fork() , execvp() ,然后通过dup()设置管道的读取文件描述符,关闭原始文件不会阻塞。 int p[2]; pipe(p); switch (fork()) { case 0: { char *argv[] = {"./output", NULL}; close(p[0]); dup2(p[1], 1); execvp(*argv, argv); } default: { close(p[1]); int d = dup(p[0]); close(p[0]); } } 为什么会发生这种情况,以及如何关闭从popen()返回的FILE *并在其位置使用文件描述符? 更新: 我知道该文档说要使用pclose() ,但是fclose()也会阻塞。 此外,我在glibc代码中打了一下,而pclose()只是调用了fclose() 。 无论使用fclose()还是pclose() ,其行为都是相同的。 回答1 http://linux.die.net/man/3
  • C 命名管道 (fifo)。 父进程卡住(C Named pipe (fifo). Parent process gets stuck)
    问题 我想做一个简单的程序,那个 fork,子进程写入命名管道,父进程从命名管道读取和显示。 问题是它进入父级,执行第一个 printf 然后它变得奇怪,它不做任何其他事情,没有到达第二个 printf,它只是在控制台中输入的方法。 #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> void main() { char t[100]; mkfifo("myfifo",777); pid_t pid; pid = fork(); if (pid==0) { //execl("fifo2","fifo2",(char*)0); char r[100]; printf("scrie2->"); scanf("%s",r); int fp; fp = open("myfifo",O_WRONLY); write(fp,r,99); close(fp); printf("exit kid \n"); exit(0); } else { wait(0); printf("entered parent \n"); // <- this it prints //
  • 使用python从子进程读取输出(Reading output from child process using python)
    问题 上下文 我正在使用subprocess模块从 python 启动一个进程。 我希望能够在写入/缓冲后立即访问输出(stdout、stderr)。 该解决方案必须支持 Windows 7。我也需要一个适用于 Unix 系统的解决方案,但我怀疑 Windows 的情况更难解决。 该解决方案应支持 Python 2.6。 我目前仅限于 Python 2.6,但仍然赞赏使用更高版本 Python 的解决方案。 该解决方案不应使用第三方库。 理想情况下,我会喜欢使用标准库的解决方案,但我愿意接受建议。 该解决方案必须适用于几乎任何流程。 假设对正在执行的进程没有控制。 子进程 例如,假设我要运行名为Python文件counter.py通过subprocess 。 counter.py的内容如下: import sys for index in range(10): # Write data to standard out. sys.stdout.write(str(index)) # Push buffered data to disk. sys.stdout.flush() 父进程 负责执行counter.py示例的父进程如下: import subprocess command = ['python', 'counter.py'] process = subprocess
  • Reading output from child process using python
    The Context I am using the subprocess module to start a process from python. I want to be able to access the output (stdout, stderr) as soon as it is written/buffered. The solution must support Windows 7. I require a solution for Unix systems too but I suspect the Windows case is more difficult to solve. The solution should support Python 2.6. I am currently restricted to Python 2.6 but solutions using later versions of Python are still appreciated. The solution should not use third party libraries. Ideally I would love a solution using the standard library but I am open to suggestions. The
  • Linux C/C++编程之(十七)进程间通信
    文章目录 一、概述二、进程间通信概念及方法1. 管道的概念2. pipe3. 管道的读写行为4. 管道缓冲区大小5. 管道优劣6. FIFO7. 共享存储映射8. mmap函数9. munmap函数10. mmap九问11. mmap父子进程间通信12. 匿名映射13. mmap无血缘关系进程间通信 3. 练习 一、概述 二、进程间通信概念及方法 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问。 要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为 进程间通信(IPC,InterProcess Communication)。 在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。 现今常用的进程间通信方式有: 1)管道 (使用最简单) 2)信号 (开销最小) 3)共享映射区 (无血缘关系) 4)本地套接字 (最稳定) 进程间通信方法介绍 1. 管道的概念 管道是一种最基本的IPC机制,作用于 有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。
  • 实验四Linux 进程之间的通信
    本文章转载地址 实验4 进程之间的通信 实验性质:验证性 实验学时:4学时 一、实验目的 1.掌握管道、信号、共享内存、消息队列等进程间通信机制; 2.能够利进程间通信机制求解一些常见问题。 二、实验预备知识 1.阅读并掌握C语言基本语法,操作。 2.熟悉Linux常用命令及使用方法。 3.实验内容 编写程序实现以下功能: 利用匿名管道实现父子进程间通信,要求 父进程发送字符串“hello child”给子进程; 子进程收到父进程发送的数据后,给父进程回复“hello farther”; 父子进程通信完毕,父进程依次打印子进程的退出状态以及子进程的pid。 源代码: 实验4 进程之间的通信 实验性质:验证性 实验学时:4学时 一、实验目的 1.掌握管道、信号、共享内存、消息队列等进程间通信机制; 2.能够利进程间通信机制求解一些常见问题。 二、实验预备知识 1.阅读并掌握C语言基本语法,操作。 2.熟悉Linux常用命令及使用方法。 3.实验内容 1. 编写程序实现以下功能: 利用匿名管道实现父子进程间通信,要求 父进程发送字符串“hello child”给子进程; 子进程收到父进程发送的数据后,给父进程回复“hello farther”; 父子进程通信完毕,父进程依次打印子进程的退出状态以及子进程的pid。 源代码: #include <unistd.h> #include
  • Win32,即使子项终止,仍从管道块读取文件(Win32, ReadFile from pipe block even after child terminated)
    问题 我有一个简单的程序(用C语言编写),该程序创建两个子进程,每个进程都在一个继承的管道上等待,然后将输出放入文件中。 一切工作正常,除了在两个管道上进行了一些写/读循环之后,当子级结束时,对ReadFile的调用块等待管道上的数据。 我使用以下模式: ... //create pipe1 CreatePipe(&hReadDup,&hWrite,&saAttr,0); DuplicateHandle(GetCurrentProcess(),hReadDup,GetCurrentProcess(),&hRead,0,FALSE,DUPLICATE_SAME_ACCESS); CloseHandle(hReadDup); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdOutput = hWrite; CreateProcess( NULL, const_cast<LPWSTR>(cmd2.c_str()), //the command to execute NULL, NULL, TRUE, 0, NULL, NULL, &si, //si. &pi ); ... CloseHandle(hWrite); // EDIT: this was the operation not properly done
  • 如何正确读取子进程的 stdout/stderr 输出?(How do I read stdout/stderr output of a child process correctly?)
    问题 我编写了一个程序a.exe ,它使用 CreateProcess 函数启动我编写的另一个程序b.exe 。 调用者创建两个管道并将两个管道的写入端作为 stdout/stderr 句柄传递给 CreateProcess 以供子进程使用。 这实际上与 MSDN 上的使用重定向输入和输出示例创建子进程相同。 由于它似乎无法使用一个同步调用来等待进程退出或stdout 或 stderr 上的数据可用(WaitForMultipleObjects 函数不适用于管道),因此调用者有两个线程正在运行两者都在 stdout/stderr 管道的读取端执行(阻塞)ReadFile 调用; 这是用于 stdout/stderr 的“读取线程过程”的确切代码(我没有自己编写此代码,我假设某些同事编写了): DWORD __stdcall ReadDataProc( void *handle ) { char buf[ 1024 ]; DWORD nread; while ( ReadFile( (HANDLE)handle, buf, sizeof( buf ), &nread, NULL ) && GetLastError() != ERROR_BROKEN_PIPE ) { if ( nread > 0 ) { fwrite( buf, nread, 1, stdout ); } }
  • Process.waitFor(),线程和InputStreams(Process.waitFor(), threads, and InputStreams)
    问题 用伪代码,这是我在做什么: Process proc = runtime.exec(command); processOutputStreamInThread(proc.getInputStream()); processOutputStreamInThread(proc.getErrorStream()); proc.waitFor() 但是,有时processOutputStreamInThread看不到任何输出,有时却看到。 大致而言,该方法创建命令输出的BufferedInputStream并将其发送到记录器。 根据我所看到的,我猜测该command不需要将所有输出都转储到由getInputStream()和getErrorStream()馈送的流中,从而允许该流为空。 我的试验结果是以下问题: (1) java.lang.Process中的waitFor() )是否要求执行程序的输出在返回之前已被读取? 该文档仅说明: 使当前线程在必要时等待,直到此Process对象表示的Process终止。 如果子进程已经终止,则此方法立即返回。 如果子进程尚未终止,则调用线程将被阻塞,直到子进程退出。 (2)在什么情况下, getInputStream和getErrorStream提供的流需要关闭和/或自动关闭? 该文档仅说明: 获取子流程的错误流。
  • java:如何通过管道(stdin / stdout)对进程进行读写(java: how to both read and write to & from process thru pipe (stdin/stdout))
    问题 (我是Java新手)我需要启动一个进程并接收2或3个句柄:对于STDIN,STDOUT(和STDERR),因此我可以将输入写入进程并接收其输出,就像命令行管道一样表现(例如“ grep”) 在Python中,可以通过以下代码实现: from subprocess import Popen, PIPE p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) (child_stdin, child_stdout) = (p.stdin, p.stdout) child_stdin.write('Yoram Opposum\n') child_stdin.flush() child_stdout.readlines() 什么是Java等价物? 到目前为止我已经尝试过 Process p = Runtime.getRuntime().exec(cmd); BufferedReader inp = new BufferedReader( new InputStreamReader(p.getInputStream()) ); BufferedWriter out = new BufferedWriter( new OutputStreamWriter(p.getOutputStream()) ); out.write( "Some
  • fork()之后如何处理execvp(…)错误?(How to handle execvp(…) errors after fork()?)
    问题 我做常规的事情: 叉() 子文件中的execvp(cmd,) 如果execvp因找不到cmd而失败,如何在父进程中注意到此错误? 回答1 为此可以采用众所周知的自管技巧。 #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/wait.h> #include <sysexits.h> #include <unistd.h> int main(int argc, char **argv) { int pipefds[2]; int count, err; pid_t child; if (pipe(pipefds)) { perror("pipe"); return EX_OSERR; } if (fcntl(pipefds[1], F_SETFD, fcntl(pipefds[1], F_GETFD) | FD_CLOEXEC)) { perror("fcntl"); return EX_OSERR; } switch (child = fork()) { case -1: perror("fork"); return EX_OSERR; case 0: close(pipefds[0]); execvp(argv[1], argv + 1)
  • Why does read block on a pipe until the write end is closed?
    I'm trying to bolster my understanding of things related to fork, exec, dup, and redirecting stdin/stdout/stderr by writing the following popen-type function: // main.c #include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #define INVALID_FD (-1) typedef enum PipeEnd { READ_END = 0, WRITE_END = 1 } PipeEnd; typedef int Pipe[2]; /** Encapsulates information about a created child process. */ typedef struct popen2_t { bool success; ///< true if the child process was spawned. Pipe stdin; ///< parent ->
  • 在 Python 中从终端读取(Read from the terminal in Python)
    问题 如何从 Python 终端接收输入? 我正在使用 Python 与另一个从用户输入生成输出的程序交互。 我正在使用 subprocess.Popen() 来输入程序,但我无法将 stdout 设置为 subprocess.PIPE 因为该程序似乎从未刷新过,因此所有内容都卡在缓冲区中。 程序的标准输出似乎是打印到终端,当我不重定向 stdout 时我会看到输出。 但是,我需要 Python 来读取和解释现在在终端中的输出。 对不起,如果这是一个愚蠢的问题,但我似乎无法让它发挥作用。 回答1 子进程中的缓冲是一个常见问题。 这里有四种可能的方法。 首先,也是最简单的方法,您可以一次从管道中读取一个字节。 这就是我所说的“肮脏的黑客”,它会带来性能损失,但它很容易,并且它保证您的 read() 调用只会阻塞直到第一个字节进入,而不是等待缓冲区填满永远不会填满。 但是,这不会强制其他进程刷新其写入缓冲区,因此如果这是问题所在,则此方法无论如何都无济于事。 其次,我认为第二个最简单的方法是考虑使用 Twisted 框架,该框架具有使用虚拟终端或 pty(我认为是“伪电传打字机”)与您的子进程对话的功能。 但是,这可能会影响您的应用程序的设计(可能会更好,但无论如何这可能不适合您)。 http://twistedmatrix.com/documents/current/core
  • c 中的 pipe() 和 fork()(pipe() and fork() in c)
    问题 我需要创建两个子进程。 一个子进程需要运行命令“ls -al”并将其输出重定向到下一个子进程的输入,该子进程将对其输入数据运行命令“sort -r -n -k 5”。 最后,父进程需要读取(数据已经排序)并将其显示在终端中。 终端中的最终结果(执行程序时)应该与我直接在 shell 中输入以下命令相同:“ls -al | sort -r -n -k 5”。 为此,我需要使用以下方法:pipe()、fork()、execlp()。 我的程序可以编译,但我没有得到终端所需的输出。 我不知道出了什么问题。 这是代码: #include <sys/types.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main() { int fd[2]; pid_t ls_pid, sort_pid; char buff[1000]; /* create the pipe */ if (pipe(fd) == -1) { fprintf(stderr, "Pipe failed"); return 1; } /* create child 2 first */ sort_pid = fork(); if (sort_pid < 0) { // error creating Child 2 process
  • 使用 Popen.wait() 时重现死锁(Reproducing deadlock while using Popen.wait())
    问题 从使用 Popen.wait() 的文档可以: 当使用 stdout=PIPE 和/或 stderr=PIPE 并且子进程向管道生成足够的输出时死锁,从而阻止等待 OS 管道缓冲区接受更多数据。 使用communication() 来避免这种情况。 在交流文档中,它写道: 读取的数据是缓存在内存中的,所以如果数据量很大或者没有限制就不要使用这种方式 如何重现这种有问题的行为并看到使用 Popen.communicate() 修复它? 死锁意味着持有资源的进程之间会发生一些循环等待并且永远卡住。 这里的循环依赖是什么? 等待子进程终止的 Python 进程是一种等待。 另一个是什么? 在下面的场景中,谁在等待什么? 它阻止等待操作系统管道缓冲区接受更多数据 回答1 这简单。 创建一个输出大量文本而不读取输出的进程: p = subprocess.Popen(["ls","-R"],stdout=subprocess.PIPE) p.wait() 一段时间后,标准输出管道已满,进程被阻塞。 这是一个死锁情况,因为子进程不能再写入输出,直到它被消耗(即:从不),并且 python 进程等待子进程完成。 为避免死锁,您可以使用读取行循环: p = subprocess.Popen(["ls","-R"],stdout=subprocess.PIPE) for line in p