2012-02-05 4 views
1

Мне поручено копировать миллионы папок по отдельности через потоки в C/C++ на Linux (с некоторым устаревшим кодом).Проблема синхронизации нити

Индивидуальные функции, такие как сканирование папок, копирование файла из папки источника в папку на месте и правильная работа при выполнении в серийном режиме. Вся проблема возникает, когда выполняется через потоки.

Ошибка: код ведет себя по-другому, каждый раз, когда я его выполняю. Иногда он копирует весь список папок 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 передается от основной функции функции потока, но в функции потока полученное значение равно 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; 
} 

Thread код функции:

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 для синхронизации потоков, а не wait-loop. –

+1

'usleep (1); // Самое главное для потокования ....... '- яркий красный флаг, который говорит мне:« Я БРОК! ». Создайте копию 'foldername' для перехода к pthread_create и освободите ее в потоке, когда вы закончите с ней. – 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 будет достаточно времени. Вместо этого вы должны сделать абсолютно , что память останется в силе до тех пор, пока другой поток не сможет ее использовать. Самый простой способ сделать это, чтобы дать другому потоку своей собственную копию данных:

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 содержания этого указателя, так что нет никакого способа узнать, что содержание какой-либо конкретная нить видит.

Вам необходимо сделать личную копию содержимого для каждого потока (затем пусть поток очистит его).

Смежные вопросы