【问题标题】:Thread synchronization issue线程同步问题
【发布时间】:2012-02-05 03:19:31
【问题描述】:

我的任务是在 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;
}

谁能帮我解决这个问题。

【问题讨论】:

  • 我建议你使用线程池模式来解决这个问题。无论如何,在你的代码中,你最好使用 std::condition_variable 来同步线程而不是等待循环。
  • usleep(1); // most crucial for threading....... 是一个明亮的红旗,它对我说:“我已经坏了!”。复制foldername 以传递给 pthread_create 并在完成后将其释放到线程中。
  • 嘻嘻吉姆,正是……!!!最好大声喊出来...... :-)

标签: c++ linux multithreading


【解决方案1】:
                    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;
}

还有其他方法可以确保线程已获取数据的副本,但这是最简单的方法。

【讨论】:

    【解决方案2】:

    作为第四个参数传递的指针不是线程安全的。

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

    因此每个线程都接收到相同的指针,并且由于主线程正在覆盖该指针的内容,因此无法知道任何特定线程看到的内容。

    您需要为每个线程制作内容的私有副本(然后让线程清理它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      相关资源
      最近更新 更多