2012-08-27 91 views
3

这是我第一次尝试使用std::future这段代码为什么会产生竞态条件?

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

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的指针为空,导致分段错误。

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

+3

没有看这个bug,这个设计看起来仍然很可怕。 'thisParserInstance'存在什么?它的名字是不正确的:它是第一个进入该函数的实例,* forever *。为什么不直接使用'this'? – GManNickG

+1

为什么这么复杂?只需将'[this]'放入捕获列表中... –

+0

@GManNickG我应该解释这一点。该功能在程序执行过程中只调用一次。我需要将解析器实例传递给3个新线程,并且我看不到任何更干净的方法。 – qdii

回答

3

的一个大问题是在这里:

static parser * thisParserInstance = this; 

这是初始化第一次调用该函数,然后保持不变的未来调用。所以,如果你在一个对象上调用该函数,销毁该对象,然后在第二个对象上调用它,你实际上正在处理一个悬挂对象的悬挂指针。这肯定会给未定义的行为。

没有理由使用静态变量; lambda可以捕获this并对正确的对象起作用。或者更简单地说,作为意见提出,使用async一个可变形式结合this的成员函数:

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

+1,谢谢。我会改变这种情况,但这不能成为bug,因为这个功能只是被故意调用一次。 – qdii

+0

不管怎样,尽管你不认为它会有帮助,但试试捕获这个ptr。我想你可能会感到惊讶。 –

+4

无论如何,'std :: async(std :: launch :: async,&parser :: parseSentences,this)'不需要使用lambda;'会正常工作。 –

1

对不起球员。

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

-lpthread链接之后,错误消失。感谢您的其他评论,但他们非常有帮助。

+0

我怀疑std :: future没有引入内存障碍。也许这就是-lpthread完成的。 –

+0

我不认为这是问题所在,代码已经链接到libpthread,因为您可以清楚地看到堆栈跟踪显示它正在从libpthread执行代码:'#18 0x00007ffff64eaec6 in start_thread()from/lib64/libpthread .so.0' –

+0

@qdii:查看[libstdC++手册](http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html)中的要求。 – Mankarse