2013-06-28 2 views
2

부스트 라이브러리를 사용하여 코드를 멀티 스레드하려고합니다. 문제는 각 스레드가 두 개의 전역 변수를 액세스하고 수정해야한다는 것입니다. 공유 리소스를 잠그기 위해 뮤텍스를 사용하고 있지만 프로그램이 멀티 스레드되지 않은 경우 더 많은 시간이 소요됩니다. 공유 액세스를 최적화하는 방법에 대한 조언이 있으십니까?C++ 멀티 스레딩 공유 리소스

고맙습니다.

아래 예제에서 * choose_ecount * 변수는 잠겨 있어야하고 루프에서 꺼내어 루프의 끝에있는 업데이트 만 잠글 수는 없습니다. 안에 기능이 있습니다. 그것은 당신이 내부 루프에서 뮤텍스를 사용하여 적절한 성능을받을거야 확률이 낮다

for(int sidx = startStep; sidx <= endStep && sidx < d.sents[lang].size(); sidx ++){ 
    sentence s = d.sents[lang][sidx]; 
    int senlen = s.words.size(); 
    int end_symb = s.words[senlen-1].pos; 

    inside(s, lbeta); 
    outside(s,lbeta, lalpha); 
    long double sen_prob = lbeta[senlen-1][F][NO][0][senlen-1]; 

    if (lambda[0] == 0){ 
     mtx_.lock(); 
     d.sents[lang][sidx].prob = sen_prob; 
     mtx_.unlock(); 
    } 

    for(int size = 1; size <= senlen; size++) 
     for(int i = 0; i <= senlen - size ; i++) 
     { 
      int j = i + size - 1; 
      for(int k = i; k < j; k++) 
      { 
       int hidx = i; int head = s.words[hidx].pos; 
       for(int r = k+1; r <=j; r++) 
       { 
        int aidx = r; int arg = s.words[aidx].pos; 
         mtx_.lock(); 
        for(int kids = ONE; kids <= MAX; kids++) 
        { 
         long double num = lalpha[hidx][R][kids][i][j] * get_choose_prob(s, hidx, aidx) * 
           lbeta[hidx][R][kids - 1][i][k] * lbeta[aidx][F][NO][k+1][j]; 
         long double gen_right_prob = (num/sen_prob); 

         choose_ecount[lang][head][arg] += gen_right_prob; //LOCK 
         order_ecount[lang][head][arg][RIGHT] += gen_right_prob; //LOCK 
        } 
         mtx_.unlock(); 
       } 

}

+2

일부 코드가 보이지 않음 ... –

+0

일부 코드에 추가되었습니다. – langLord

+1

가장 안쪽 루프에서 뮤텍스를 들어 올려 레벨 위로 옮길 수 있습니까? –

답변

0

. 동시 프로그래밍은 프로그래머뿐만 아니라 컴퓨터에서도 어렵습니다. 최신 CPU 성능의 상당 부분은 코드 블록을 외부 데이터와 독립적 인 시퀀스로 처리 할 수 ​​있다는 점에서 비롯됩니다. 단일 스레드 실행에 효율적 인 알고리즘은 종종 다중 스레드 실행에 적합하지 않습니다.

자물쇠가없는 동기화를 제공 할 수있는 boost::atomic을보고 싶지만 원자 조작에 필요한 메모리 장벽은 여전히 ​​무료가 아니므로 문제가 계속 발생할 수 있습니다. - 당신의 알고리즘을 생각해보십시오.

1

게시 한 코드에서 볼 수있는 것은 choose_ecount 및 order_ecount에만 기록 할 수 있습니다. 그래서 sum을 계산하기 위해 로컬 당 쓰레드 버퍼를 사용하고 가장 바깥 쪽 루프 다음에 이것을 추가하고 왜이 연산만을 동기화할까요?

편집 : 중간 값인 choose_ecount에 액세스해야한다면 올바른 중간 값이 어떻게 표시되는지 어떻게 알 수 있습니까? 한 스레드가 다른 스레드에서 다른 결과를 생성하는 동안 루프의 두 반복을 완료했을 수 있습니다.

계산 대신 장벽을 사용해야하는 것 같습니다.

0

전체 스레드를 startStep에서 endStep까지의 범위로 나누면 각 스레드에서 처리 할 수 ​​있습니다.

거기에 잠겨 있기 때문에 모든 스레드를 효과적으로 직렬화 할 수 있습니다. 문제를 직렬로 처리하는 일부 청크로 나눕니다. 멀티 스레딩을 수행하는 데 오버 헤드 만 있으면됩니다.

double s에서 작업하고 있으므로 원자 연산은 선택 사항이 아닙니다. 일반적으로 정수 유형에만 구현됩니다.

유일하게 가능한 해결책은 각 스레드에 대해 choose_ecountorder_ecount 사본을 갖고 스레드가 완료된 후 단일 스레드로 축소하는 Kratz의 제안을 따르는 것입니다.