2015-02-07 3 views
0

코드를 게시하고 내가 수행하고 있다고 생각하는 내용을 알려줄 것입니다.std :: list를 수정하기위한 C++ 11 스레드

#include <thread> 
#include <mutex> 
#include <list> 
#include <iostream> 

using namespace std; 

... 

//List of threads and ints 
list<thread> threads; 
list<int> intList; 

//Whether or not a thread is running 
bool running(false); 

//Counters 
int busy(0), counter(0); 

//Add 10000 elements to the list 
for (int i = 0; i < 10000; ++i){ 
    //push back an int 
    intList.push_back(i); 
    counter++; 
    //If the thread is running, make a note of it and continue 
    if (running){ 
     busy++; 
     continue; 
    } 
    //If we haven't yet added 10 elements before a reset, continue 
    if (counter < 10) 
     continue; 
    //If we've added more than 10 ints, and there's no active thread, 
    //reset the counter and launch 
    counter = 0; 
    threads.push_back(std::thread([&] 
     //These iterators are function args 
     (list<int>::iterator begin, list<int>::iterator end){ 
     //mutex for the running bool 
     mutex m; 
     m.lock(); 
     running = true; 
     m.unlock(); 

     //Remove either 10 elements or every element till the end 
     int removed(0); 
     while (removed < 10 && begin != end){ 
      begin = intList.erase(begin); 
      removed++; 
     } 

     //unlock the running bool 
     m.lock(); 
     running = false; 
     m.unlock(); 
     //Pass into the thread func the current beginning and end of the list 
    }, intList.begin(), intList.end())); 
} 

for (auto& thread : threads){ 
    thread.join(); 
} 

이 코드가 수행하는 것으로 생각하는 것은 목록 끝에 10000 개의 요소를 추가하는 것입니다. 추가 할 때마다 목록의 처음 10 개 요소를 삭제하는 (단일 스레드) 스레드를 시작합니다 (스레드가 시작될 때).

나는 모든 목록 요소를 제거하지 않을 것이라고 생각합니다. 처음부터 요소를 제거하는 동안 목록의 끝에 추가 할 수 있는지보고 싶었습니다. Visual Studio에서 "list iterators incompatible"오류가 자주 발생하지만 크로스 플랫폼 문제라고 생각합니다.

내 생각에 무슨 문제가 있습니까?

그래서이 코드는 매우 잘못 이니까 참조 : 나는

이 편집 뭔가를 알고있다. 정말로 한 번에 하나의 보조 스레드를 활성화하여 요소를 삭제하고 싶습니다. 이유는 삭제를 호출해도 괜찮습니다. 그러나 나는 그것을 결합하지 않고 스레드를 선언하는 방법을 모르겠다. 그리고 내가 그것을 기다리고 있다면, 나는이 일을하는 시점을 정말로 보지 못한다.

루프 전에 내 스레드를 선언하고 주 스레드의 신호를 기다려야합니까?

명확한 목표는 다음과 같습니다. 하나의 스레드에서 키보드 누름을 가져 와서 목록에 저장하고 모든 스레드를 분리 스레드에서 파일에 기록합니다. 들어갔다. 디스크에 많은 시간을 쓰고 싶지 않기 때문에 이산 청크 (10 개)로 작성하고 싶습니다.

Christophe와 그 밖의 모든 사람들에게 감사드립니다. 여기에 내 코드가 있습니다 ... 나는 lock_guard를 잘못 사용하고있을 수 있습니다.

#include <thread> 
#include <mutex> 
#include <list> 
#include <iostream> 
#include <atomic> 

using namespace std; 

... 

atomic<bool> running(false); 
list<int> intList; 
int busy(0), counter(0); 
mutex m; 
thread * t(nullptr); 

for (int i = 0; i < 100000; ++i){ 
    //Would a lock_guard here be inappropriate? 
    m.lock(); 
    intList.push_back(i); 
    m.unlock(); 
    counter++; 
    if (running){ 
     busy++; 
     continue; 
    } 
    if (counter < 10) 
     continue; 
    counter = 0; 
    if (t){ 
     t->join(); 
     delete t; 
    } 
    t = new thread([&](){ 
     running = true; 

     int removed(0); 
     while (removed < 10){ 
      lock_guard<mutex> lock(m); 
      if (intList.size()) 
       intList.erase(intList.begin()); 
      removed++; 
     } 
     running = false; 
    }); 
} 

if (t){ 
    t->join(); 
    delete t; 
} 
+0

erm, 각 스레드는 무의미한 자체 뮤텍스를 가지고 있습니다 ... – Nim

+1

'begin = intList.erase (begin);'첫 번째 스레드가이를 수행하면 다른 모든 스레드로 전달되는 반복자는 유효하지 않게됩니다.메인 쓰레드에서'begin()'호출, worker에서'erase()'호출, 다양한 iterator 호출 사이에 경쟁이 있습니다. 이 코드는 작동 할 희망이 없습니다. –

+0

먼저 문제를 해결하기 전에 컴파일러 오류를 수정하십시오. –

답변

1

때문에 작동하지 않습니다 귀하의 코드 :

  • 뮤텍스는 각 스레드의 로컬 (각 스레드는 그 자체 만 사용 자신의 복사본입니다 있습니다! interthread 동기화없이 기회)
  • intList는 원자형이 아니지만 경쟁 조건과 정의되지 않은 동작을 유발하는 여러 스레드에서 액세스합니다.
  • 생성시 스레드에 보내는 시작과 끝은 더 이상 실행 중에 유효하지 않을 수 있습니다. 여기

일부 개선 (주석 라인을 보려면) : 그런데

atomic<bool> running(false); // <=== atomic (to avoid unnecessary use of mutex) 
int busy(0), counter(0); 
mutex l; // define the mutex here, so that it will be the same for all threads 

for (int i = 0; i < 10000; ++i){ 
    l.lock(); // <===you need to protect each access to the list 
    intList.push_back(i); 
    l.unlock(); // <===and unlock 
    counter++; 
    if (running){ 
     busy++; 
     continue; 
    } 
    if (counter < 10) 
     continue; 
    counter = 0; 
    threads.push_back(std::thread([&] 
     (){ //<====No iterator args as they might be outdated during executionof threads!! 
     running = true; // <=== no longer surrounded from lock/unlock as it is now atomic 

     int removed(0); 
     while (removed < 10){ 
      l.lock();  // <====you really need to protect access to the list 
      if (intList.size()) // <=== check if elements exist NOW 
       intList.erase(intList.begin()); // <===use current data, not a prehistoric outdated local begin !! 
      l.unlock();  // <====end of protected section 
      removed++; 
     } 

     running = false; // <=== no longer surrounded from lock/unlock as it is now atomic 
    })); //<===No other arguments 
} 
... 

, 나는이 잠금 해제를 보장 당신이, 잠금에 대한 lock_guard<mutex> 한 번 봐 가지고 좋을 것 모든 상황에서 (특히 이와 같은 예외 또는 놀라움이있을 때).

편집 : 나는 atomic<bool>으로 뮤텍스와 함께 running의 잠금 보호를 피했습니다.

+0

감사합니다. 나의 주된 혼란은 왜 내가 메인 스레드 밖에서 하나 이상의 스레드를 필요로 하는가이다. 내가 처음부터 끝까지 통과 한 이유는 스레드가 삭제해야하는 미리 정의 된 범위의 요소를 원했기 때문이며 주 스레드가 더 많은 요소를 계속 추가하는 동안 한 스레드 만 처리하도록했습니다. 당신은 제 질문에 대한 대답을했지만, 저는 처음부터 잘못 생각하고 있다고 생각합니다. 고맙습니다. – user1973454

관련 문제