readline 与子 printf 冲突?

发布于 2024-09-24 23:54:28 字数 1164 浏览 0 评论 0原文

在Linux中,readline()在无限循环中重复读取文本\n。但是,一旦子进程开始打印到屏幕,readline 就不再读取新行。即使我反复按 Enter 键,readline() 也不会返回。

有谁知道出了什么问题吗?

根据要求的代码示例:

char* input;
int cpid;
while(1)
{
     input = readline(">>>");
     strcpy(tempInput, input); //...does some stuff w/ tempInput
     //....
     cpid = fork();
     if(cpid == 0){
           printf("..."); printf("...");
           execl("ls", "ls", "-l", (char*) NULL); //sample execl parameters
     }
     else{
           //do some stuff...
           printf("...");
     }
     free(input);
}

    //readline(">>>") works the first time and doesn't return on subsequent calls

代码挂起位置的堆栈跟踪(永远):

Thread [1] (Suspended : Signal : SIGINT:Interrupt)  
    __read_nocancel() at ../sysdeps/unix/syscall-template.S:82 0x7ffff78f0490   
    rl_getc() at 0x7ffff7bc3727 
    rl_read_key() at 0x7ffff7bc3c90 
    readline_internal_char() at 0x7ffff7baf25f  
    readline() at 0x7ffff7baf795    
    main() at /home/.../.../xxx.c:95 0x4010a1   

编辑:对于经验丰富的 UNIX 开发人员来说,这可能听起来完全是技术问题,但是子进程是否可能以某种方式“捕获”了 stdin 并且无法以某种方式释放它?

In Linux, readline() in an infinite loop repeatdly reads text\n. However, as soon as child processes start printing to the screen, readline no longer reads new lines. Even if I repeatdly press enter, readline() doesn't return.

Anyone know what's wrong?

Code sample as requested:

char* input;
int cpid;
while(1)
{
     input = readline(">>>");
     strcpy(tempInput, input); //...does some stuff w/ tempInput
     //....
     cpid = fork();
     if(cpid == 0){
           printf("..."); printf("...");
           execl("ls", "ls", "-l", (char*) NULL); //sample execl parameters
     }
     else{
           //do some stuff...
           printf("...");
     }
     free(input);
}

    //readline(">>>") works the first time and doesn't return on subsequent calls

The stacktrace of where the code hangs (forever):

Thread [1] (Suspended : Signal : SIGINT:Interrupt)  
    __read_nocancel() at ../sysdeps/unix/syscall-template.S:82 0x7ffff78f0490   
    rl_getc() at 0x7ffff7bc3727 
    rl_read_key() at 0x7ffff7bc3c90 
    readline_internal_char() at 0x7ffff7baf25f  
    readline() at 0x7ffff7baf795    
    main() at /home/.../.../xxx.c:95 0x4010a1   

Edit: This probably sounds like total technobabble to experienced unix developers, but could the child process have somehow 'captured' stdin and fail to release it somehow?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你的心境我的脸 2024-10-01 23:54:28

即使在执行之后,您的子进程仍然将其标准输入连接到您的终端。使用 wait() 等待子进程完成,或者将子进程的标准输入重新打开为 /dev/null

close(STDIN_FILENO) && open("/dev/null", "O_WRONLY");

Your child processes, even after exec, still has its standard input connected to your terminal. Either use wait() to wait for the child process to finish, or reopen the child's standard input as /dev/null:

close(STDIN_FILENO) && open("/dev/null", "O_WRONLY");
ぺ禁宫浮华殁 2024-10-01 23:54:28

在 fork() 之后,您的子进程执行 2 个 printf 调用,然后继续执行 while(1) 循环,因此您所做的是在每个换行符后创建 1 个额外的进程。

您需要做的是,在打印 2 个省略号 (...) 后立即杀死子进程,

将代码更改为:

  if(cpid == 0){
        printf("..."); printf("..."); exec(...); exit(0); 
    }

请记住,仅当 exec() 时才调用 exit()失败。

编辑:

如果您打算接受某种命令行解释器的输入,readline 不是一个很好的选择。它的官方手册页说:

BUGS:

    It’s too big and too slow.

我可以建议一种获取输入字符串的替代方法:

char c;
inputString = calloc(0,sizeof(char));
inputLength = 0;

c = getchar();
    while(c!='\n')
    {
        inputString = realloc(inputString,(inputLength+1)*sizeof(char));
        inputString[inputLength++] = c;
        c = getchar();
    }
    inputString[inputLength] = '\0';

现在你在 inputString & 中有字符串了。它的长度在 inputLength 中。您很可以这样做:

execlp(inputString,inputString,0);

执行所需的功能。

After you fork(), your child process executes the 2 printf calls, then goes on to execute the while(1) loop, so what you are doing is creating 1 extra process after every newline.

What you need to do, is kill the child immediately after it prints the 2 ellipses (...)

Change your code to this:

  if(cpid == 0){
        printf("..."); printf("..."); exec(...); exit(0); 
    }

Bear in mind, exit() is called only if the exec() fails.

Edit:

If you intend to accept input for some kind of command line interpreter, readline isn't a very good option. Its official man page says:

BUGS:

    It’s too big and too slow.

I could suggest an alternative way of getting the input string:

char c;
inputString = calloc(0,sizeof(char));
inputLength = 0;

c = getchar();
    while(c!='\n')
    {
        inputString = realloc(inputString,(inputLength+1)*sizeof(char));
        inputString[inputLength++] = c;
        c = getchar();
    }
    inputString[inputLength] = '\0';

Now you have the string in inputString & its length in inputLength. You could very well do:

execlp(inputString,inputString,0);

to execute the required functionality.

合久必婚 2024-10-01 23:54:28

这段代码不起作用,因为您对 execl() 的调用失败,因此子进程将在循环代码处恢复,该循环代码也将使用 readline()。

使用 execl() 时,必须传递可执行文件的完整路径,或者使用 execlp() 变体(搜索 PATH 环境变量)才能使其正常工作。

即使对于最简单的系统调用,始终检查其返回码也是一个好习惯。

This piece of code is not working because your call to execl() is failing, therefore the child process will resume at the loop code, which will also be using readline().

You must pass the full path to the executable when using execl(), or use the execlp() variant (which search into PATH environment variable) for it to work.

Even for the simplest syscalls, it's a good practice to always check for their return codes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文