0

In these snippets the go program tries to write to C program's stdin. The problem is that the c program starts an infinite loop after the go loop finishes.

main.c

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


int main(){
    int age;
    char name[8]; 

    for(;;)
    {
    scanf(" %s : %d\n",&name, &age);
    printf("%s : %d\n",name, age);
    }
    return 0;
}

run/main.go

func main() {

    proc := exec.Command("../main")
    stdin, err := proc.StdinPipe()
    if err != nil {
        fmt.Println(err) 
    }

    defer stdin.Close()

    proc.Stdout = os.Stdout
    proc.Stderr = os.Stderr

    fmt.Println("START")                      
    if err = proc.Start(); err != nil { 
        log.Fatal("An error occured: ", err)
    }

    for i := 0; i < 500; i++ {
        io.WriteString(stdin, fmt.Sprintf("hello : %d\n", i))
        //How to wait here and read from printf()?
    }

    //proc.Process.Kill() Here proc gets killed too fast

    fmt.Println("END")
}

When killed, process doesn't complete it's output

Output

START
END
hello : 497
hello : 498
hello : 499
hello : 499 

Output Expected

START
....
hello : 497
hello : 498
hello : 499
END
ned
  • 71
  • 2
  • 9
  • 2
    check for the scanf return value – pm100 Feb 09 '22 at 19:40
  • 2
    You forwarded the `stdout` of the child process to the standard output of your process. If you don't want that, don't do that and read from the `proc.Stdout`. Or have the child program send a signal when it's done. – Cheatah Feb 09 '22 at 19:42
  • 1
    Remove the `\n` from the `scanf`: https://stackoverflow.com/questions/15443483/using-n-in-scanf-in-c – kaylum Feb 09 '22 at 19:43
  • 1
    You need to coordinate with the child process in some way, read stdout, have it exit if you close stdin, etc. The C program enters an infinite loop when you close stdin without the Go program too, because that's what you wrote in the C program. – JimB Feb 09 '22 at 19:44
  • 2
    `for(;;)` is an infinite loop since there's nothing in it to break out. Use the return value from `scanf` to determine that it failed and break there. – Retired Ninja Feb 09 '22 at 19:47
  • @pm100 c starts looping when scanf gets -1 – ned Feb 09 '22 at 20:02
  • 1
    so exit the loop, it means the sending program has ended – pm100 Feb 09 '22 at 21:07
  • Go program gets stuck reading the data manually using ioutil.Readall() from stdoutPipe. Any hints? – ned Feb 09 '22 at 22:04
  • `ReadAll` blocks until the stream is closed. (EOF) You never close `stdout`. – Zyl Feb 09 '22 at 23:01

1 Answers1

0

After reading the comments and few more searching I have worked it out. On C program I removed \n from scanf() and added fflush(stdout) after printf. According to this page I changed them to these:

int main(){
    int age;
    char name[8]; 

    int ret;

    for(;;)
    {
    ret= scanf("%s : %d",&name, &age);
    if (ret == -1) {
        break;
    }
    printf("%s : %d\n",name, age);

    fflush(stdout);
    }
    
    return 0;
}
func main(){
    proc := exec.Command("../main")

    stdin, err := proc.StdinPipe()
    if err != nil {
        fmt.Println(err)
    }

    reader, err := proc.StdoutPipe()
    if err != nil {
        fmt.Println(err)
        return
    }

    scanner := bufio.NewScanner(reader)
    resp := make(chan string)

    go func() {
        for scanner.Scan() {
            resp <- scanner.Text()
        }
    }()

    err = proc.Start()
    if err != nil {
        fmt.Fprintln(err)
        return
    }
    fmt.Println("START")

    for i := 0; i < 500; i++ {
        io.WriteString(stdin, fmt.Sprintf("hello : %d\n", i))

        v := <-resp
        print(v+"\n")

    }

    err = proc.Process.Kill()

    if err != nil {
        fmt.Fprintln(err)
        return
    }
    fmt.Println("END")

}
ned
  • 71
  • 2
  • 9