2012-02-05 3 views
1

저는 Linux에서 C/C++ (일부 레거시 코드 포함)의 스레딩을 통해 수백만 개의 폴더를 개별적으로 복사하는 작업을 제공 받았습니다.스레드 동기화 문제

폴더 검색, 원본에서 대상 폴더로의 파일 복사와 같은 개별 기능이 있으며, 연속적으로 실행하면 제대로 작동합니다. 스레딩을 통해 완료되면 모든 문제가 발생합니다.

문제 : 코드는 실행될 때마다 약간 다르게 작동합니다. 때로는 폴더 전체 목록을 proeprly로 복사하지만 때로는 실패합니다.

실패한 샘플 출력은 다음 함수에

foldername is [Junk] tCount is 2 cntr is 3 

val of folder is Junk tid is 3055356816 

foldername is [Notes] tCount is 3 cntr is 4 

val of folder is tid is 3042966416 

Folder creation failed /var/anshul/work/copyDirectoryThreaded/test_copied/email/ 

통과 인수의 값 NULL 스레드된다. 위의 경우에는 Notes 인수가 main 함수에서 thread 함수로 전달되었지만 thread 함수에서 수신 된 값은 NULL입니다.

내 주요 코드는 다음과 같습니다

int main() 
{ 
    int cntr=0; 
    int Val = 3; 

    tCount = 0; 
    pthread_t thread[folderCount]; // folderCount is total number of folders scanned 
    int iret[folderCount]; 
    std::map<std::string,int>::iterator mFolderIt; // mFolder map contains the folder list. 
    char foldername[30] = {0}; 

    for (mFolderIt=mFolder.begin() ; mFolderIt != mFolder.end();) 
    { 
     if(tCount < Val) 
     { 
      pthread_mutex_lock(&mutex_tCount); 
      tCount++; 
      pthread_mutex_unlock(&mutex_tCount); 

      sprintf(foldername,"%s",(*mFolderIt).first.c_str()); 
      fprintf(stderr, "foldername is [%s] tCount is %d cntr is %d\n",foldername,tCount,cntr); 
      iret[cntr] = pthread_create(&thread[cntr], NULL,folderCopy , (void*)foldername); 
      cntr++; 
      usleep(1); // most crucial for threading....... 
      mFolderIt++; 
      memset(foldername,0,30); 
     } 
     else 
     { 
      while(tCount >= Val) 
      { 
       usleep(10); 
      } 
     } 
    } 

    for(int x = 0 ; x<folderCount ;x++) 
     pthread_join(thread[x],NULL); 

    return 1; 
} 

스레드 기능 코드 :

void * folderCopy(void *f) 
{ 
    fprintf(stderr,"val of folder is %s tid is %u\n", folder, (unsigned int)pthread_self()); 

    pthread_mutex_lock(&mutex_tCount); 
    tCount--; 
    pthread_mutex_unlock(&mutex_tCount); 
    pthread_exit(NULL); 
    return NULL; 
} 

누군가가 나에게이 문제를 해결하는 데 도움이 바랍니다 수 있습니다.

+0

문제를 해결하기 위해 스레드 풀 패턴을 사용하는 것이 좋습니다. 어쨌든, 코드에서 대기 루프보다는 스레드를 동기화하는 데 std :: condition_variable을 사용하는 것이 더 좋습니다. –

+1

'usleep (1); // 스레딩에 가장 중요합니다 ....... "는 나에게 밝히고있는 밝은 붉은 깃발이다 :"나는 깨졌어! ". pthread_create에 전달하기 위해'foldername'의 사본을 만들고, 쓰레드가 끝날 때 쓰레드에서 해제하십시오. – JimR

+0

heehe Jim, 정확히 ... !!! 큰소리로 외치는 것이 더 낫습니다. :-) –

답변

3
    fprintf(stderr, "foldername is [%s] tCount is %d cntr is %d\n",foldername,tCount,cntr); 
        iret[cntr] = pthread_create(&thread[cntr], NULL,folderCopy , (void*)foldername); 
        cntr++; 
        usleep(1); // most crucial for threading....... 
        mFolderIt++; 
        memset(foldername,0,30); 

usleep 충분한 시간이 될 것이라는 guarentee 없습니다. 대신 을 반드시으로 설정하여 다른 스레드가 사용할 수있을 때까지 메모리를 유효하게 유지해야합니다. 이 작업을 수행하는 가장 간단한 방법은 다른 스레드에게 데이터의 복사본을 제공하는 것입니다 :

iret[cntr] = pthread_create(&thread[cntr], NULL, folderCopy, strdup(foldername)); 
// ... 

void * folderCopy(void *f) 
{ 
    char *folderName = (char *)f; 
    // do something with folderName 
    free(f); 
    return NULL; 
} 

이 스레드가 데이터의 사본을 촬영되었는지 확인하는 다른 방법이 있지만,이 얻을 수있는 간단합니다 권리.

+0

감사합니다. bdonlan .. 그게 .. ..-). –

1

네 번째 매개 변수로 전달 된 포인터는 스레드로부터 안전하지 않습니다.

pthread_create(&thread[cntr], NULL,folderCopy , (void*)foldername); 

그래서 모든 스레드가 동일한 포인터를 수신하고 특정 스레드가 보는 것을 내용 알 수있는 방법이 없기 때문에 메인 스레드 때문에이 포인터의 내용을 overwritting된다.

각 스레드에 대해 콘텐츠의 비공개 사본을 만들어야합니다. 그러면 스레드가이를 정리합니다.