2012-08-27 2 views
3

이것은 내 첫 시도 인 std::future입니다.이 코드가 경쟁 조건을 만드는 이유는 무엇입니까?

나는 동시에 세 가지 다른 파일을 분석하고 싶습니다. 세 가지 기능이 있습니다. parseSentences, parseTagsparseLinks이라고합니다. 이들 각각은 매우 간단한 람다 함수 인 []() { parser->function(); }을 사용하여 std::async을 사용하는 별도의 스레드에서 실행됩니다. 여기서 parser은 정적 변수이고 function은 이전에 이름을 지정한 세 가지 함수 중 하나입니다. 내가 GDB 내 프로그램을 실행할 때

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

지금, 세그먼트 오류는 std::future 지역 변수 중 하나의 파괴에서 발생한다. 그 순간에 2 개의 스레드가 실행 중입니다. 스레드 # 1의 호출 스택은 here입니다. 스레드 # 2의 호출 스택은 here입니다.

첫 번째 호출 스택의 this에 대한 포인터가 null이므로 세그먼트 화 오류가 발생합니다.

아무도 단서가 있다면, 나는 감사 할 것이다.

+3

버그를 보지 않고도이 디자인은 여전히 ​​무서운 것처럼 보입니다. 'thisParserInstance'는 무엇입니까? 이름이 정확하지 않습니다. 함수의 인스턴스 인 * forever *를 처음 입력하는 것입니다. 'this'를 직접 사용하지 않겠습니까? – GManNickG

+1

왜 그렇게 복잡합니까? 캡쳐리스트에'[this]'를 넣으십시오 ... –

+0

@GManNickG 그걸 설명해야합니다. 이 함수는 프로그램 실행 중에 한 번만 호출됩니다. 파서 인스턴스를 3 개의 새 스레드에 전달해야했기 때문에 더 깨끗한 방법으로 작업을 수행 할 수 없었습니다. – qdii

답변

3

하나의 큰 문제는 여기에 있습니다 : 다음 함수를 호출 처음 초기화하고있어

static parser * thisParserInstance = this; 

미래의 통화에서 변경되지. 그래서 하나의 객체에서 함수를 호출하고, 그 객체를 파괴 한 다음 두 번째 객체에서 호출하면 실제로 존재하지 않는 객체에 매달려있는 포인터로 작업하게됩니다. 확실히 정의되지 않은 동작을 제공합니다.

정적 변수를 사용할 이유가 없습니다. 람다는 this을 붙잡고 정확한 물체에 작용할 수 있습니다. 코멘트에 제안 또는 더 간단하게, 멤버 함수에 this 바인딩 async의 가변 양식을 사용 :

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

+1, 감사합니다. 나는 그것을 바꿀 것이다. 그러나 이것은 의도적으로 함수가 한 번만 호출되기 때문에 버그가 될 수 없다. – qdii

+0

어쨌든 도움이된다고 생각하지 않더라도 this-ptr을 캡처하십시오. 나는 네가 놀랄 것 같아. –

+4

어쨌든 람다를 사용할 필요가 없습니다.'std :: async (std :: launch :: async, & parser :: parseSentences, this);는 정상적으로 작동합니다. –

1

죄송합니다들. 여기

이 솔루션입니다 : std::future exception on gcc experimental implementation of C++0x

-lpthread로 연결 한 후, 오류가 사라졌다. 귀하의 다른 발언에 감사드립니다, 그들은 매우 도움이되었다.

+0

나는 std :: future가 메모리 장벽을 도입하지 않는다고 생각했다. 어쩌면 그것이 -lpthread가 성취하는 것일 수도 있습니다. –

+0

그게 문제라고 생각하지 않습니다. 코드가 이미 libpthread에 링크되어 있습니다. 스택 추적 중 하나가 libpthread에서 코드를 실행하고 있음을 분명히 알 수 있습니다.'/ lib64/libpthread의 start_thread()에서 # 18 0x00007ffff64eaec6 .so.0' –

+0

@qdii : [libstdC++ 매뉴얼] (http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html)의 요구 사항을 살펴보십시오. – Mankarse

관련 문제