为什么这段代码会产生竞争条件?

时间:2012-08-27 22:12:03

标签: c++ multithreading c++11 race-condition

这是我第一次尝试使用std::future

我有三个不同的文件要同时解析。三个功能就是这样做的。称为parseSentencesparseTagsparseLinks。通过使用一个非常简单的lambda函数std::async,使用[]() { parser->function(); }在每个单独的线程中启动它们,其中parser是一个静态变量,函数是我命名的三个函数之一先前。

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;
}

现在,当我在gdb中运行程序时,在销毁std::future局部变量之一时会发生分段错误。这一刻有2个线程在运行。 线程#1的调用堆栈是here。 线程#2的调用堆栈是here

请注意,第一个调用堆栈中指向this的指针为空,从而导致分段错误。

如果有人有线索,我会很感激。

2 个答案:

答案 0 :(得分:3)

这里有一个大问题:

static parser * thisParserInstance = this;

首次调用该函数时初始化,然后在未来的调用中保持不变。因此,如果您在一个对象上调用该函数,销毁该对象,然后在第二个对象上调用它,您实际上正在处理一个指向已解除对象的悬空指针。这肯定会给出不明确的行为。

没有理由使用静态变量; lambdas可以捕获this并对正确的对象采取行动。或者更简单地,如评论中所建议的,使用async的可变形式将this绑定到成员函数:

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

答案 1 :(得分:1)

对不起伙计们。

这是解决方案:std::future exception on gcc experimental implementation of C++0x

-lpthread关联后,错误消失了。谢谢你的其他评论,但他们非常乐于助人。