Linux下的C语言多线程编程:并发处理文本文件(使用POSIX标准)

分类:
标签:
分享到:

Linux的二号人物 Alan Cox 曾评论线程为“如何立刻让自己自讨苦吃”,某C在自己尝试编写多线程代码的时候也走了一些弯路,现在写出来和大家分享。

某C的实验室项目需要处理大量结构化文本文件,原先的单线程版本处理速度比较慢。最近打算开发一个查找用的分支版本,于是想到使用多线程并发来提速。

最开始考虑的是使用grep+sed+awk来完成,因为仅仅是查找文本文件而已。后来发现文本里有碍事的换行符,某C对于shell又极度不熟悉,只好作罢。

于是开始学习Linux下的多线程编程。项目现在的实现方法是先生成一个待读取的文件列表,接着轮流去读取文件。

改成多线程的思路也很简单,就是单独让各个线程去读取不同的文件,以此来实现加速。这里最重要的问题便是如何互斥访问文件列表。好在Linux已经有了很方便的互斥锁mutex来完成这个任务。

main函数代码如下
    int res;//系统函数返回值
    pthread_t a_thread[NUM_THREADS];//线程数组
    void *thread_result;//线程返回值
    int lots_of_threads;//计数
    res=pthread_mutex_init(&path_mutex,NULL);//初始化互斥锁
    for(lots_of_threads=0;lots_of_threads<NUM_THREADS;lots_of_threads++)
    {
        res=pthread_create(&(a_thread[lots_of_threads]),NULL,thread_func,(void*)lots_of_threads);//产生线程,thread_func是要执行的线程函数
        
    }
    printf("waiting for thread to finish...\n");
    for(lots_of_threads=NUM_THREADS-1;lots_of_threads>=0;lots_of_threads--)
    {
        res=pthread_join(a_thread[lots_of_threads],&thread_result);//等待线程结束
        if(res==0)
        {
            printf("pick up a thread\n");
        }
        else
        {
            perror("pthread_join failed");
        }
    }
    printf("all done\n");

thread_func代码:
void *thread_func(void *arg)
{
    int my_num=(int)arg;//线程编号
    cout<<"thread "<<my_num<<" runing\n";
    pthread_mutex_lock(&path_mutex);//申请一个互斥锁
    
    while(!pathvector.empty())//文件列表放在一个vector中,轮询判断是否为空
    {
        const char *fullfilepath=(*pathvector.rbegin()).c_str();
        cout<<"thread "<<my_num<<" get "<<fullfilepath<<endl;//
        pathvector.pop_back();
        //上面三行从vector里获取一个文件路径,然后从vector里删除
        pthread_mutex_unlock(&path_mutex);//获取完了,可以释放互斥锁了
        
        readmetafile(fullfilepath,hostmap,logfp,malfp);//★处理文件★
        
        pthread_mutex_lock(&path_mutex);//处理完了,再申请一个锁,准备处理下一个文件
    }
    pthread_mutex_unlock(&path_mutex);//vector空了,释放锁
    printf("bye from %d\n",my_num);
    pthread_exit(NULL);//线程退出
}

某C本来在“☆处理文件☆”这一步时没有释放锁,导致每次都是0号线程独自处理所有文件,其他线程只能干等在一边。后来觉得处理文件的时候不需要保证互斥,不如把锁释放掉,没想到真的成功了。

经测试在10个线程的情况下,和单线程相比,多线程版本的程序仅仅使用了1/5的时间,提速效果相当明显!

这个例子本身很简单,其他多线程处理互斥访问的问题也可以触类旁通。如果上面的描述或者代码有什么问题,请各位大牛斧正!

你可能还会对下列文章感兴趣: