2012-02-05 60 views
1

我已經通過Linux上的C/C++線程(有一些遺留代碼)通過線程單獨拷貝了數百萬個文件夾。線程同步問題

像掃描文件夾,將文件從源文件複製到目標文件夾等各項功能都已到位,並且在串行執行時可以正常工作。整個問題通過線程完成。

問題:每次執行代碼時,代碼的行爲都會有所不同。有時它會複製整個文件夾列表,但有時會失敗。

的樣品失敗輸出是:

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已從主函數傳遞到線程函數,但在線程函數中,接收的值爲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來同步線程而不是等待循環。 – 2012-02-05 03:39:31

+1

'usleep(1); //對穿線最爲關鍵.......'是一面鮮紅的旗幟,對我說:「我是破產!」製作一份'foldername'作爲傳遞給pthread_create的一個拷貝,並在你完成之後將它釋放到線程中。 – JimR 2012-02-05 03:58:43

+0

heehe Jim,正是...... !!!它更好地大聲喊... :-) – 2012-02-05 04:58:38

回答

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將足夠的時間。相反,你應該確保內存將保持有效,直到其他線程有機會使用它。要做到這一點,最簡單的辦法是給其他線程它自己的數據副本:

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 ..那工作.. :-) – 2012-02-05 04:18:15

1

作爲第四個參數傳遞的指針不是線程安全的。

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

所以,每個線程接收相同的指針,因爲主線程,所以沒有辦法知道任何特定線程看到什麼內容overwritting該指針的內容。

您需要爲每個線程創建內容的私人副本(然後讓線程清理它)。