qdii
qdii

Reputation: 12963

Why does this code produce a race condition?

This is my first attempt at using std::future.

I have three different files that I want to parse at the same time. Three functions do that, resp. called parseSentences, parseTags and parseLinks. Each of them is launched in a separate thread using std::async by using a very simple lambda function: []() { parser->function(); }, where parser is a static variable and function is one of the three functions I have named previously.

int parser::start()
{
    int ret = SUCCESS;
    ASSERT( m_output != nullptr );
    static parser * thisParserInstance = this;

    // parsing files
    std::future<int> parseSentence = std::async(std::launch::async, []() { return thisParserInstance->parseSentences(); } );
    std::future<int> parseLinksResult = std::async(std::launch::async, []() { return thisParserInstance->parseLinks(); } );
    std::future<int> parseTagsResult = std::async(std::launch::async, []() { return thisParserInstance->parseTags(); } );

    // retrieving the results
    ret = parseSentence.get();
    const int linksResult = parseLinksResult.get();
    const int tagsResult = parseTagsResult.get();

    if (ret == SUCCESS)
        ret = linksResult == SUCCESS ? tagsResult : linksResult;

    return ret;
}

Now when I run my program in gdb, a segmentation fault occurs at the destruction of one of the std::future local variable. There are 2 threads running at that moment. Thread #1’s call stack is here. Thread #2’s call stack is here.

Note that the pointer to this in the first call stack is null, resulting in the segmentation fault.

If anyone has a clue, I would be thankful.

Upvotes: 3

Views: 806

Answers (2)

Mike Seymour
Mike Seymour

Reputation: 254461

One big problem is here:

static parser * thisParserInstance = this;

That's initialised the first time you call the function, and then left unchanged on future calls. So if you call the function on one object, destroy that object, and then call it on a second object, you'll actually be working on a dangling pointer to the defunct object. That will certainly give undefined behaviour.

There's no reason to use a static variable; the lambdas can capture this and act on the correct object. Or more simply, as suggested in the comments, use the variadic form of async to bind this to the member function:

std::async(std::launch::async, &parser::parseSentences, this);

Upvotes: 3

qdii
qdii

Reputation: 12963

Sorry guys.

here is the solution: std::future exception on gcc experimental implementation of C++0x

After linking with -lpthread, the error disappeared. Thanks for your other remarks, though, they were very helpful.

Upvotes: 1

Related Questions