2017-11-09 13 views
0

나는 장벽 클래스를 구현하려고 시도했다. 분할 및 정복 알고리즘을 사용하여이를 테스트하고 싶습니다. 내 클래스는 다음과 같이 정의된다 : 분할에 관해서는divide and conquer (바쁜 동안 뮤텍스가 파괴됨)를 사용하는 배리어 클래스 C++

class barrier{ 
private: 
    mutex mtx; 
    condition_variable cv; 
    atomic<int> counter; 
    atomic<int> waiting; 
    atomic<int> thread_count; 

public: 
    barrier(int count) : thread_count(count), counter(0), waiting(0) {} 

    void wait() 
    { 
     //fence mechanism 
     unique_lock<mutex> lock(mtx); 
     ++counter; 
     ++waiting; 
     cv.wait(lock, [&] {return counter >= thread_count; }); 
     --waiting; 
     if (waiting == 0) counter = 0; 
     for (int i = 0; i < thread_count; ++i) cv.notify_one(); 
     lock.unlock(); 
    } 
}; 

및 알고리즘을 정복 다음, 나는 그것을 구현했습니다 : 이것은 그러나 "바쁜 동안 파괴 뮤텍스"결과

int main() { 
    vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 
    int n = size(v)/2; 

    while (n >= 1) { 
     dnc_light(v, n); 
     n /= 2; 
    } 

    return 0; 
} 

void dnc_light (vector<int> &v, int n) { 
    thread trd[50]; 
    barrier bar(n); 

    for (int i = 0; i < n; ++i) { 
     trd[i] = thread([&] { 
      v[i] += v[i + n]; 
      bar.wait(); 
     }); 
    } 
} 

- 오류 . 어째서? 동적으로 barrier bar(...)의 크기를 처리해야합니다.

답변

2

그러나이 때문에 "사용 중 파괴 된 뮤텍스"오류가 발생합니다. 어째서?

dnc_light 로컬 barrier 개체에 대한 참조와 함께 여러 스레드가 생성됩니다. 그런 다음 함수는 해당 스레드가 여전히 사용중인 로컬 barrier을 파괴하여 "사용 중 파괴 된 뮤텍스"오류를 발생시킵니다.

또한 스레드는 결합 가능하므로 소멸자는 결합되거나 분리되지 않으므로 예외를 발생시킵니다.

수정 사항은 함수에서 반환하기 전에 스레드에 가입하는 것입니다 :

void dnc_light(vector<int> &v, int n) { 
    vector<thread> trd(n); 
    barrier bar(n); 

    for (int i = 0; i < n; ++i) { 
     trd[i] = thread([&](){ 
      v[i] += v[i + n]; 
      bar.wait(); 
     }); 
    } 

    for(auto& t : trd) 
     t.join(); 
} 

을 위의 코드에서이 루프 대기에 참여하기 때문에 모든 스레드 어쨌든 종료까지 전혀 장벽이 필요하지 않습니다. barrier에서


변수는 뮤텍스를 잡고 그것은 단지 그들에 액세스하기 때문에 원자 할 필요가 없습니다. 단순화 :

class barrier { 
    mutex mtx; 
    condition_variable cv; 
    int const thread_count; 
    int counter{0}; 
    int waiting{0}; 

public: 
    barrier(int count) : thread_count(count) {} 

    void wait() { 
     unique_lock<mutex> lock(mtx); 
     ++counter; 
     ++waiting; 
     cv.wait(lock, [&](){ 
      return counter >= thread_count; 
     }); 
     if(waiting == thread_count) 
      cv.notify_all(); 
     if(!--waiting) 
      counter = 0; 
    } 
}; 
+0

방금 ​​테스트 해본 결과 제안 사항이 적용되었습니다. 두 가지 질문이 있습니다 : 단지'dnc_light'에 스레드를 결합하는 대신 분리 할 수 ​​있습니까? 어제 주 코드에서 모든 것을 코딩 해 보았습니다.하지만 동일한 오류가 발생했습니다. for-loop 이후에 장벽이 파손 되었기 때문입니까? – SAFD

+0

@SAFD 연결을 피하기 위해 스레드를 분리 할 수 ​​있습니다. 그러나이 경우 장벽이 살아 있는지 확인해야합니다. 이를 수행하는 한 가지 방법은'auto barrier = make_shared (n);'이며 쓰레드에 값으로'barrier' 스마트 포인터를 넘겨 사용 중에도 살아있게합니다. –

+0

그래, 너무 복잡해서 나 두렵다. 몇 가지 추가 테스트를 한 결과, 합계가 항상 136이 아닌 것으로 나타났습니다. 때때로 스레드가 계산을 엉망으로 만듭니다. 그래서'dnc_light'를 변경했습니다 : 이제'v' byvalval을 잡아서 합계를 저장하는'temp'라는 벡터를 갖습니다. 이로 인해 문제가 해결되었습니다. 지금 내가 얻는 유일한 오류는 임의의 합계가 결국 '0'이된다는 것입니다. – SAFD