简体   繁体   English

Popen不起作用后,C程序会挂在Fget上

[英]C Program Hangs on Fgets after Popen doesn't work

EDIT : I wrote a C program that generates invertible functions and writes them into R files that are executed and opened with popen . 编辑 :我编写了一个C程序,该程序生成可逆函数,并将它们写入R文件中,这些文件将通过popen执行并打开。 I am running this program on Ubuntu 16.04. 我正在Ubuntu 16.04上运行此程序。 My program compiles, but the R script never finishes/hangs 我的程序可以编译,但是R脚本永远不会完成/挂起

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define num_func 10

char * makeInvert(){
    char * buffer = malloc(200 * sizeof(char));
    double a = (double)(rand()%5)-5.0; 
    double b = (double)(rand()%5)-5.0; 
    double c = (double)(rand()%5)-5.0; 
    double n = (double)(rand()%5)-5.0;
    n *= 2;
    n += 1;
    sprintf(buffer, "%g(x + %g)^%g + %g == y", a, b, n, c);
    return buffer;

}

int main() {
  printf("entered main \n");
  int i;
  char * buff1;

  for (i = 0; i < num_func; i++) {
        char R[5000];
    buff1 = makeInvert();

    strcpy(R, "library(Ryacas)\n");
    strcat(R, "yacas(\"Solve(");
    strcat(R, buff1);
    strcat(R, ", x)\")\n\n");
    //sleep(1);
    char filename[100];
    strcpy(filename, "computation/");
    strcat(filename, "inverse");
    strcat(filename, ".R");
    FILE * f = fopen(filename, "w");    
    if (!f) {       //validate file is open 
            printf("cant open file");
     }
    fputs(R, f);
    printf("before fclose");
    fflush(stdout);
    fclose(f);
        f = NULL;
    printf("after fclose");
    fflush(stdout);

    char path[5000];
    char command[300];
    strcpy(command,"Rscript ");
    strcat(command, "computation/inverse");

    strcat(command, ".R");
    printf("command %s\n", command);
    FILE * fp = popen(command, "r");

    if (!fp) {       //validate file is open 
            printf("cant open file");
            fflush(stdout);
     }

    printf("after popen\n");
    fflush(stdout);

    while (fgets(path, sizeof(path)-1, fp) != NULL) {
           printf("output: %s\n", path);

        }
    fclose(fp);

  }
  return 0;
}

Output from running strace -f program_name 运行strace -f program_name输出

execve("/usr/bin/test", ["test"], [/* 20 vars */]) = 0
brk(NULL)                               = 0x16ef000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f95f15a9000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=53425, ...}) = 0
mmap(NULL, 53425, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f95f159b000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, ...}) = 0
mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f95f0fbc000
mprotect(0x7f95f117c000, 2097152, PROT_NONE) = 0
mmap(0x7f95f137c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7f95f137c000
mmap(0x7f95f1382000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f95f1382000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f95f159a000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f95f1599000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f95f1598000
arch_prctl(ARCH_SET_FS, 0x7f95f1599700) = 0
mprotect(0x7f95f137c000, 16384, PROT_READ) = 0
mprotect(0x60a000, 4096, PROT_READ)     = 0
mprotect(0x7f95f15ab000, 4096, PROT_READ) = 0
munmap(0x7f95f159b000, 53425)           = 0
brk(NULL)                               = 0x16ef000
brk(0x1710000)                          = 0x1710000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1668976, ...}) = 0
mmap(NULL, 1668976, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f95f1400000
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

When I run Rscript computation/inverse.R directly, it hangs and doesn't output anything. 当我直接运行Rscript computation/inverse.R ,它挂起并且不输出任何内容。


I believe it is hanging on the fgets because when I run the program on gdb for the backtrace, I see this: 我相信它挂在fgets上,因为当我在gdb上为回溯运行程序时,会看到以下内容:

after popen 
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7b04230 in __read_nocancel ()
    at ../sysdeps/unix/syscall-template.S:84
84  ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) backtrace
#0  0x00007ffff7b04230 in __read_nocancel ()
    at ../sysdeps/unix/syscall-template.S:84
#1  0x00007ffff7a875e8 in _IO_new_file_underflow (fp=0x6034f0) at fileops.c:592
#2  0x00007ffff7a8860e in __GI__IO_default_uflow (fp=0x6034f0) at genops.c:413
#3  0x00007ffff7a7bc6a in __GI__IO_getline_info (fp=fp@entry=0x6034f0, 
    buf=buf@entry=0x7fffffffd1d0 "", n=4998, delim=delim@entry=10, 
    extract_delim=extract_delim@entry=1, eof=eof@entry=0x0) at iogetline.c:60
#4  0x00007ffff7a7bd78 in __GI__IO_getline (fp=fp@entry=0x6034f0, 
    buf=buf@entry=0x7fffffffd1d0 "", n=<optimized out>, delim=delim@entry=10, 
    extract_delim=extract_delim@entry=1) at iogetline.c:34
#5  0x00007ffff7a7ab7d in _IO_fgets (buf=0x7fffffffd1d0 "", n=<optimized out>, 
    fp=0x6034f0) at iofgets.c:53
#6  0x0000000000401288 in main () at test.c:123
(gdb) frame 6
#6  0x0000000000401288 in main () at test.c:123
123     while (fgets(path, sizeof(path)-1, fp) != NULL) {

After reading this post , I added this code after I popen 阅读这篇文章后 ,我在popen后添加了此代码

    int fd = fileno(fp);

    int flags;
    flags = fcntl(fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(fd, F_SETFL, flags);

The post explains that, "In Linux (or any Unix-y OS), you can mark the underlying file descriptor used by popen() to be non-blocking. [Using the above code] if there is no input available, fgets will return NULL with errno set to EWOULDBLOCK." 该帖子解释说:“在Linux(或任何Unix-y OS)中,您可以将popen()使用的基础文件描述符标记为非阻塞。[使用上面的代码]如果没有可用的输入,fgets将errno设置为EWOULDBLOCK时返回NULL。” When I run gdb now, I get: 现在运行gdb时,我得到:

after popen 
^C
Program received signal SIGINT, Interrupt.
0x00007ffff785f188 in _IO_new_proc_close (fp=0x6034f0) at iopopen.c:339
339 iopopen.c: No such file or directory.
(gdb) bt
#0  0x00007ffff785f188 in _IO_new_proc_close (fp=0x6034f0) at iopopen.c:339
#1  0x00007ffff7869960 in _IO_new_file_close_it (fp=fp@entry=0x6034f0) at fileops.c:172
#2  0x00007ffff785d3ef in _IO_new_fclose (fp=0x6034f0) at iofclose.c:58
#3  0x00000000004013f9 in main () at test.c:130
(gdb) frame 3
#3  0x00000000004013f9 in main () at test.c:130
130     fclose(fp);
(gdb) 

I didn't went through the entire code, but I spotted this flaw: 我没有遍历整个代码,但是发现了这个缺陷:

char R[5000];
buff1 = makeInvert();
strcat(R, "library(Ryacas)\n");
strcat(R, "yacas(\"Solve(");

You strcat -ing "library..." onto an uninitialized string. strcat -ing“库......”在一个未初始化字符串。 You should use strcpy for the first string as you did it elsewhere or insert R[0]='\\0'; 您应该像在其他地方一样对第一个字符串使用strcpy或插入R[0]='\\0'; .

If you use non-blocking I/O, fgets() will exit as soon as no output is available. 如果您使用非阻塞I / O,则fgets()将在没有可用输出时立即退出。 That does not seem to be what you want. 那似乎不是您想要的。 You want to read the whole output then exit. 您想读取整个输出然后退出。 I would recommend removing the fcntl() part. 我建议删除fcntl()部分。

The issue seems to be that your R script is not finishing. 问题似乎是您的R脚本尚未完成。 I would recommend running your program through strace -f and post the output. 我建议您通过strace -f运行程序并发布输出。 Also, have you tried to run "Rscript computation/inverse.R" directly and make sure it does return the output you're expecting and is exiting (if not fgets will get stuck)? 另外,您是否尝试过直接运行“ Rscript Calculation / inverse.R”,并确保它确实返回了您期望的输出正在退出(如果没有,则fgets会卡住)? When your process gets blocked, did you see if the Rscript is still running (I expect it does and that's why your process is stuck) 当您的进程被阻塞时,您是否看到Rscript是否仍在运行(我希望它还在运行,这就是您的进程卡住的原因)

You're still have some unrelated issues: you're closing the popen() fd with fclose(), instead of pclose(). 您仍然有一些不相关的问题:您正在使用fclose()而不是pclose()关闭popen()fd。 If fopen(filename, "w") fails, you do not exit so it'll crash. 如果fopen(filename,“ w”)失败,则不退出,否则将崩溃。

the current posted code seems to have been edited since the comments and prior answer were posted. 自发布评论和先前的答案以来,当前发布的代码似乎已被编辑。

To avoid confusion, ADD edits, do not overlay the original question. 为避免混淆,请添加编辑内容,请勿覆盖原始问题。

when calling any of the heap allocation functions (malloc, calloc, realloc) 调用任何堆分配函数(malloc,calloc,realloc)时

  • the expression: sizeof(char) is defined as 1 and multiplying anything by 1 has no effect. 表达式: sizeof(char)定义为1,将任何内容乘以1都无效。 Suggest removing that expression. 建议删除该表达式。
  • always check (!=NULL) the returned value to assure the operation was successful 始终检查(!= NULL)返回值以确保操作成功
  • When some operation fails, any error message should be output to stderr , not stdout so use perror() which will also output the reason the OS thinks the operation failed. 当某些操作失败时,任何错误消息都应该输出到stderr ,而不是stdout因此请使用perror() ,这也将输出OS认为操作失败的原因。

After announcing an unrecoverable error event, the program should exit, not continue on as if everything were 'good'. 宣布不可恢复的错误事件后,程序应退出,而不要像一切正常一样继续进行。

it is poor programming practice to include header files that are not being used. 包含未使用的头文件的编程习惯很差。 Suggest removing the include statements for: math.h and fctrl.h 建议删除以下内容的include语句: math.hfctrl.h

when using popen() , the resulting file descriptor pointer should be closed via pclose() , not fclose() 使用popen() ,应通过pclose()而不是fclose()关闭生成的文件描述符指针

I took the latest posted code and performed several simplifications and corrections, resulting in the following: 我采用了最新发布的代码,并进行了一些简化和更正,结果如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define num_func 10


char * makeInvert( void );


char * makeInvert()
{
    char * buffer = malloc(200);
    if( !buffer )
    {
        perror( "malloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    double a = (double)(rand()%5)-5.0;
    double b = (double)(rand()%5)-5.0;
    double c = (double)(rand()%5)-5.0;
    double n = (double)(rand()%5)-5.0;
    n *= 2;
    n += 1;
    sprintf(buffer, "%g(x + %g)^%g + %g == y", a, b, n, c);
    return buffer;
} // end function: makeInvert


int main( void )
{
    printf("entered main \n");
    int i;
    //char * buff1;

    for (i = 0; i < num_func; i++)
    {
        FILE * f = fopen( "inverse.R", "w");
        if (!f)
        {       //validate file is open
                //printf("cant open file");
                perror( "fopen for computation/inverse.R for write failed" );
                exit( EXIT_FAILURE );
        }

        // implied else, fopen successful

        char R[5000];

        strcpy(R, "library(Ryacas)\nyacas(\"Solve(");
        strcat(R, makeInvert());
        strcat(R, ", x)\")\n\n");
        fputs(R, f);

        //printf("before fclose\n");
        //fflush(stdout);
        fclose(f);
        f = NULL;

        //printf("after fclose\n");
        //fflush(stdout);

        //char command[300];
        //strcpy(command, "Rscript computation/inverse.R");
        //printf("command %s\n", command);

        FILE * fp = popen( "Rscript inverse.R", "r");
        if (!fp)
        {       //validate file is open
                //printf("cant open file");
                //fflush(stdout);
                perror( "popen for inverse.R for read failed" );
                exit( EXIT_FAILURE );
        }

        // implied else, popen successful

        //printf("after popen\n");
        //fflush(stdout);

        char path[5000];
        while (fgets(path, sizeof(path)-1, fp) != NULL)
        {
               printf("output: %s\n", path);
        }

        //fclose(fp);
        pclose( fp );
    }
    return 0;
}

Amongst other things, note the consistent indenting, for the purpose of readability. 其中,为了便于阅读,请注意一致的缩进。 The compiler doesn't care, but us humans do. 编译器不在乎,但是我们人类在乎。

Note: R is not installed on my linux 16.04 注意:我的Linux 16.04上未安装R

The resulting .R file contains: 生成的.R文件包含:

library(Ryacas)
yacas("Solve(-2(x + -4)^-5 + -4 == y, x)")

the output from running the modified code is: 运行修改后的代码的输出为:

entered main 
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found
sh: 1: Rscript: not found

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM