代码之家  ›  专栏  ›  技术社区  ›  qdii

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

  •  3
  • qdii  · 技术社区  · 13 年前

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

    我有三个不同的文件,我想同时解析。分别有三个函数可以做到这一点。调用 parseSentences , parseTags parseLinks 。它们中的每一个都在单独的线程中启动,使用 std::async 通过使用一个非常简单的lambda函数: []() { 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::未来 局部变量。此时有2个线程正在运行。 线程#1s调用堆栈为 here 。 线程#2s调用堆栈为 here

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

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

    2 回复  |  直到 13 年前
        1
  •  3
  •   Mike Seymour    13 年前

    这里有一个大问题:

    static parser * thisParserInstance = this;
    

    它在您第一次调用函数时初始化,然后在以后的调用中保持不变。因此,如果您在一个对象上调用该函数,销毁该对象,然后在第二个对象上进行调用,那么实际上您正在处理一个指向已失效对象的悬挂指针。这肯定会导致不明确的行为。

    没有理由使用静态变量;lambdas可以捕捉 this 并作用于正确的对象。或者更简单地说,正如评论中所建议的,使用 async 绑定 到成员功能:

    std::async(std::launch::async, &parser::parseSentences, this);
    
        2
  •  1
  •   Community CDub    8 年前

    对不起,伙计们。

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

    与链接后 -lpthread ,错误消失了。不过,谢谢你的其他评论,它们非常有帮助。