2012-09-17 6 views
7

나는 람다에 루프 변수 매개 변수가있는 for 루프 안에 람다를 가지고 있습니다. 내가 그것을 실행할 때, 나는 숫자 0-9가 출력되기를 기대한다. 그러나 람다이므로 x는 즉시 평가되지 않습니다.루프 내 람다

for(int x = 0; x < n; ++x) 
    { 
      vec.push_back(thread{[&x](){ 
        m.lock(); 
        cout << x << endl; 
        m.unlock(); 
      }}); 
    } 

출력 :

0 
3 
3 
9 

다른 언어에 대한 해결책은 임시 변수를 생성하는 것,

for(int x = 0; x < n; ++x) 
    { 
      int tmp = x; 
      vec.push_back(thread{[&tmp](){ 
        m.lock(); 
        cout << tmp << endl; 
        m.unlock(); 
      }}); 
    } 

하지만이 작동하지 않는 것 . 답변에 대한 내 검색에서

, 나는 반복자를 무효화 할 용기를 사용하지 않는 것이 좋습니다이 질문에 Generalizing C++11 Threads class to work with lambda 우연히 :

Threads receiving wrong parameters

이 보너스를 참조하십시오.

vec.push_back(std::thread{[x](){ 
    m.lock(); 
    std::cout << x << std::endl; 
    m.unlock(); 
}}); 

이 람다 객체가 생성 된 시점에 x의 값을 복사합니다 : 당신이 복사본을 만들려면 왜 것이라고 에 의해 대신 참조/

답변

11

캡처를 지정할 때 값으로 캡처와 참조로 캡처 중에서 선택할 수 있습니다. 참조로 캡처하도록 선택했습니다. 참조로 캡처한다는 것은 람다 함수 내부의 변수가 동일한 객체를 참조하고 있음을 의미합니다. 이 변수에 대한 변경 사항은 공유 될 것이므로 참조 된 객체가 람다 함수의 수명 동안 머물러 있는지 확인해야합니다.

아마도 값으로 캡처하려고했을 것입니다. 이렇게하려면 캡처 사양을 [=]으로 바꾸거나 [x]이 될 수 있습니다. 후자는 x 만 액세스 할 수 있으며 전자는 다른 변수에 액세스 할 수 있도록 허용합니다.

BTW, 나는 잠금 가드 중 하나를 사용하여 명시 적으로 오히려 lock()unlock()를 사용 하지을 권하고 싶습니다. 이것으로 루프의 몸체는 다음과 같이 보일 것입니다 :

vec.push_back(std::thread{[x](){ 
    std::lock_guard<std::mutex> kerberos(m); 
    std::cout << x << "\n"; 
}}); 
+0

나는 바보 같은 기분이 든다. 나는 람다 표현에서 &가 무엇을했는지 오해했다. 이 단순화 된 예에서 그렇습니다. lock_guard가 적절할 것입니다. 그러나 실제 응용 프로그램에서 함수는 잠글 필요가없는 많은 작업을 수행합니다. 이 경우 뮤텍스는 중요한 부분 주위에서만 적절한 잠금 및 잠금 해제가 될 것입니다. – SaulBack

+5

@SaulBack : 아니요. 어느쪽으로 든'lock_guard'를 사용해야합니다. 특정 코드 만 잠그고 싶다면'{} '와 함께 명시 적 블록을 사용하여 잠긴 코드를 묶으십시오. 이것은 기본 RAII 코딩입니다. –

+1

@SaulBack : 특히 복잡한 코드에서 RAII를 사용하려고합니다. 예 :'std :: lock_guard '! 이 ** 사소한 ** 예제에서 나는 그것이 필요하지 않다는 것을 알 수 있지만, 조금 더 복잡한 것은 빨리 벗어나게됩니다. 잠금이 유지되는 범위를 제한해야하는 경우 범위 (즉, {{<잠금 및 코드가 필요합니다>}')를 사용하십시오. –

6

캡처 매개 변수 수 (스레드가 시작된 시점이 아님).

답을 찾기 위해이 질문에 대한 답을 얻었습니다. 반복기를 무효로 할 컨테이너를 사용하지 말 것을 권장하는 lambda와 함께 작동하도록 C++ 11 스레드 클래스를 일반화했습니다. 그 이유는/

입니다. 이는 pthreads 라이브러리를 직접 사용하는 완전히 다른 구현에 대한 이야기이기 때문입니다. C++에서 작동하도록 설계된 std::thread을 사용하고 있습니다.

+0

std :: thread가 작동하는 동안 컨테이너의 pthead가 작동하지 않는 이유를 자세히 설명해 주시겠습니까? 복사 생성자, 이동 생성자, 대입 연산자의 문제입니까? – SaulBack

3

문제는 참조로 x를 캡처하는 것입니다. 따라서 각 루프의 끝에서 x가 증가하면 스레드에 반영됩니다.

람다가 생성 될 때 람다가 x 값만 사용하도록 값으로 x 값을 캡처하려고합니다.

for(int x = 0; x < n; ++x) 
{    
    vec.push_back(thread{[x](){ 
     m.lock(); 
     cout << tmp << endl; 
     m.unlock(); 
    }}); 
}