samedi 25 décembre 2021

How to properly read and parse piped stream on thread

I am writing a program that uses 2 threads in C++, the first one that waits for commands and prints the outputs on std::cout asynchronously and the second one that gathers this output and parses it via a pipe.

firstThread = std::thread([] () {
    Lib::loop(); // waits for commands from cin `(getline(cin, ...))`, does its magic and prints the output
});

CONSOLE OUTPUT: 
> first result 
> second result 
> third result
...

To pass those informations to a second thread I close std::cout, open a pipe, and redirect it to the second one via a file descriptor

int read_out_fd;
int write_out_fd;

int vals[2];
pipe(vals);
read_out_fd = vals[0];
write_out_fd = vals[1];

close(STDOUT_FILENO);  
dup(write_out_fd)

using the read() method in the second thread I wait for those outputs to be written by firstThread, gather them as they come, and parse them to build an array of string.

readThread = std::thread([] () {
    #define MAX_LEN 10
    char buffer[MAX_LEN+1] = {0};
    string output;
    vector<string> messages;
    
    while(read(read_out_fd, buffer, MAX_LEN)) {
        output += buffer;
        
        if(strlen(buffer) < MAX_LEN)
            output += '\n';
        
        memset(buffer, 0, sizeof buffer);
        
        if (output.find('\n')) {
            stringstream stream(output);
            string message;
            vector<string> messages_buffer;
            while(getline(stream, message)){
                messages_buffer.push_back(message);
            }
            
            output = messages_buffer.back();
            messages_buffer.pop_back();
            messages.insert( messages.end(), messages_buffer.begin(), messages_buffer.end());
        }
    }
});

This actually works, it transforms the stream of outputs from the first thread into an array (vector) of strings as they come:

messages : { "first result", "second result", "third result" }

However, I can feel that this method is convoluted. I am new to c++ and I don't know if this is the proper way to tackle this problem. Is there a better/easier way to gather and parse this output?

Notes:

  1. I cannot modify anything inside Lib::loop, this is a third part library.
  2. I cannot fork() either since this c++ code is embedded in an iOS project (or I didn't find how)
  3. I tried all the methods on this post but none of them worked for me for various reasons (missing libraries such as boost which I don't want to use, c++11 requirements etc...)

Aucun commentaire:

Enregistrer un commentaire