• Skip to main content
  • Skip to primary sidebar
  • Skip to footer
  • About
  • Life
  • Tech
  • Travel
  • Work
  • Questions
  • Contact

Welcome

.

pipe() and fork() example: basic_string::M_construct null not valid

April 10, 2020 by

Questions › pipe() and fork() example: basic_string::M_construct null not valid
0
Vote Up
Vote Down
Garmaine asked 3 years ago

Another try with getting parallel processes to work. Please excuse the amount of code but every attempt to shorten it makes the error vanish.

What I tested so far:

  • sending int from parent to child, from child to parent, and from parent to child and then back: works
  • processing a list of int: send from parent to child, modify and back to parent: works
  • more data: int + string, from parent to child, modify and back to parent: works
  • a list of data the same way: works

But when I run the same function that works a second time it always fail.

This is the function that creates the child process:

//parent sends binary data from list to child which sends back modified data
bool processParallel6(std::vector<std::pair<int, std::string>> & data)
{
    //define pipe
    int parent2Child[2];
    int child2Parent[2];

    //create pipe
    pipe(parent2Child);
    pipe(child2Parent);

    //fork
    pid_t child = fork();

    if(child == 0) //child process
    {
        //close not needed end of pipe
        close(parent2Child[1]);
        close(child2Parent[0]);

        for(;;)
        {
            struct pollfd pfd;
            pfd.fd = parent2Child[0];
            pfd.events = POLLIN;

            //wait until data is available at the pipe
            cout << "c: poll ..." << endl;
            if(poll(&pfd, 1, -1) < 0)
            {
                cout << "c: poll: " << strerror(errno) << endl;
                exit(-1);
            }
            cout << "c: poll says there are data" << endl;

            if((pfd.revents&POLLIN) == POLLIN)
            {
                int data;
                std::string text;
                if(!readData3(parent2Child[0], data, text))
                    exit(-2);
                cout << "c: data received: " << data << " " << text <<  endl;

                if(data == -1)
                    break;

                if(!writeData3(child2Parent[1], data * 2, text + text))
                    exit(-3);
                cout << "c: sent data to parent: " << 2 * data << " " << text + text << endl;
            }
        }

        close(parent2Child[0]);
        close(child2Parent[1]);
        exit(0);
    }
    else //parent process
    {
        //close not needed end of pipe
        close(parent2Child[0]);
        close(child2Parent[1]);

        //send data to child
        if(!writeData3(parent2Child[1], data.back().first, data.back().second))
            return false;
        cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
        data.pop_back();

        //read result from child
        for(;;)
        {
            struct pollfd pfd;
            pfd.fd = child2Parent[0];
            pfd.events = POLLIN;

            //wait until data is available at the pipe
            cout << "p: poll ..." << endl;
            if(poll(&pfd, 1, -1) < 0)
            {
                cout << "p poll: " << strerror(errno) << endl;
                return false;
            }
            cout << "p: poll says there are data" << endl;

            if((pfd.revents&POLLIN) == POLLIN)
            {
                int data;
                std::string text;
                if(!readData3(child2Parent[0], data, text))
                    return false;
                cout << "p: data received: " << data << " " << text << endl;
            }

            if(data.empty())
                break;

            if(!writeData3(parent2Child[1], data.back().first, data.back().second))
                return false;
            cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
            data.pop_back();
        }

        //send stop data
        if(!writeData3(parent2Child[1], -1, "notext"))
            return false;
        cout << "p: sent stop data " << endl;

        //wait for child to end
        wait(nullptr);

        //close all pipes
        close(parent2Child[1]);
        close(child2Parent[0]);
    }

    return true;
}

For reading and writing data I use this two functions:

bool readData3(int fd, int & number, std::string & text)
{
    char numberBuf[sizeof(int)];
    int bytesRead = read(fd, numberBuf, sizeof(int));
    if(bytesRead > 0)
    {
        number = *(int *)numberBuf;
    }
    else if(bytesRead < 0)
    {
        cout << "readData3: " << strerror(errno) << endl;
        return false;
    }

    char sizeBuf[sizeof(int)];
    int size = -1;
    bytesRead = read(fd, sizeBuf, sizeof(int));
    if(bytesRead > 0)
    {
        size = *(int *)sizeBuf;
    }
    else if(bytesRead < 0)
    {
        cout << "readData3: " << strerror(errno) << endl;
        return false;
    }

    char textBuf[size];
    bytesRead = read(fd, textBuf, size);
    if(bytesRead > 0)
    {
        text = std::string(textBuf);
    }
    else if(bytesRead < 0)
    {
        cout << "readData3: " << strerror(errno) << endl;
        return false;
    }
    return true;
}

bool writeData3(int fd, const int number, const std::string text)
{
    int bytesWritten = write(fd, &number, sizeof(int));
    if(bytesWritten < 0)
    {
        cout << "writeData3: " << strerror(errno) << endl;
        return false;
    }

    int size = text.size() + 1;
    bytesWritten = write(fd, &size, sizeof(int));
    if(bytesWritten < 0)
    {
        cout << "writeData3: " << strerror(errno) << endl;
        return false;
    }

    bytesWritten = write(fd, text.c_str(), size);
    if(bytesWritten < 0)
    {
        cout << "writeData3: " << strerror(errno) << endl;
        return false;
    }

    return true;
}

Finally I run it like this:

#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <bitset>
#include <memory>
#include <poll.h>
#include <cstring>

using namespace std;

int main(int /*argc*/, char* /*argv*/[])
{
    std::vector<std::pair<int, std::string>> data;
    data.push_back(std::make_pair(1, "one"));
    data.push_back(std::make_pair(2, "two"));
    cout << "6a ########################################################" << endl << flush;
    processParallel6(data);
    cout << "6b ########################################################" << endl << flush;
    processParallel6(data);

    return 0;
}

This is the output:

6a ###############################################
p: wrote data: 2 two
p: poll ...
c: poll ...
c: poll says there are data
c: data received: 2 two
p: poll says there are data
p: data received: 4 twotwo
p: wrote data: 1 one
p: poll ...
c: sent data to parent: 4 twotwo
c: poll ...
c: poll says there are data
c: data received: 1 one
p: poll says there are data
p: data received: 2 oneone
p: sent stop data 
c: sent data to parent: 2 oneone
c: poll ...
c: poll says there are data
c: data received: -1 notext
6b ###################################################
c: poll ...
terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
c: poll says there are data
c: poll ...
c: poll says there are data
c: poll ...

The last 4 lines are repeated a thousands of times. This output comes most of the times, but sometimes I have seen a std::bad_alloc error. When I try strace it crashes too, but when it runs I have seen directly after the second run of processParallel6() a line with mmap, ENOEM and 'Cannot allocate memory'

What happens here? Why is it working the first time, but not the second time?

Are you looking for the answer?
Original Question and Possible Answers can be found on `http://stackoverflow.com`

Question Tags: c++, fork, pipe

Please login or Register to submit your answer




Primary Sidebar

Tags

Advancements architecture beautiful life best building calling city commercial convenience employment Finances Cognitive decline Future gadgets Hidden Gems highway Home houses hydration Impact Innovations lamp lighting Mental health military tech Must-See New York City occupation Productivity recreation romance sepia shopping sippy cups smartphones social Technological breakthroughs technology toddlers Treasures turns Uncover Well-being Wonders Work Young onset dementia

Newsletter

Complete the form below, and we'll send you all the latest news.

Footer

Footer Funnies

Who knew that reading the footer could be such a hilarious adventure? As we navigate websites, books, and documents, we often stumble upon the unassuming space at the bottom, only to discover a treasure trove of amusement. In this side-splitting compilation, we present 100 jokes that celebrate the unsung hero of content – the footer. Get ready to chuckle, giggle, and maybe even snort as we dive into the world of footnotes, disclaimers, and hidden comedic gems. Brace yourself for a wild ride through the footer!

Recent

  • Unveiling the Enigma: Almost-Magical Lamp Lights Highway Turns
  • The Impact of Young Onset Dementia on Employment and Finances: Optimizing Post-Diagnostic Approaches
  • 11 Wonders of 2023 Technological Breakthrough – Unveiling the Future
  • Work from Home and Stay Mentally Sane – Achieve Productivity and Well-being
  • Hidden Gems of New York City – Uncover the Must-See Treasures!

Search

Tags

Advancements architecture beautiful life best building calling city commercial convenience employment Finances Cognitive decline Future gadgets Hidden Gems highway Home houses hydration Impact Innovations lamp lighting Mental health military tech Must-See New York City occupation Productivity recreation romance sepia shopping sippy cups smartphones social Technological breakthroughs technology toddlers Treasures turns Uncover Well-being Wonders Work Young onset dementia

Copyright © 2023