【问题标题】:Concurrency in PthreadPthread 中的并发
【发布时间】:2013-02-18 02:58:05
【问题描述】:

我有一个在 Linux 内核 2.6.18-194 中运行的 c 程序,服务器有 1 个带有 6 核的超线程 CPU 套接字,线程 1 接收数据,然后线程 2 和线程 3 将线程 1 接收到的数据传递给另一个进程,线程 2 之后线程3成功传递数据,线程1将再次接收数据!!

流是thread1源:

        DoGetDataFromSocket() ;
        iGlbBOOKReadDone = 0 ;
        iGlbPOSIReadDone = 0 ;
        sem_post(sembook) ;
        sem_post(semposi) ;
        sem_wait(semfinished) ;

以下是thread2和thread3的源码:

    if(bThisThreadIsBook==1)
        sem_wait(sembook) ;
    else
        sem_wait(semposi) ;

    DoPassDatatoAnotherProcess() ;

    if(bThisThreadIsBook==1)
    {
        __sync_add_and_fetch(&iGlbBOOKReadDone,1) ;
    }
    else
    {
        __sync_add_and_fetch(&iGlbPOSIReadDone,1) ;
    }

    Pthread_mutex_lock(&DoneMutex) ;
    if(  (iGlbBOOKReadDone == 1) && (iGlbPOSIReadDone == 1) )
        sem_post(semfinished) ;
    Pthread_mutex_unlock(&DoneMutex) ;

它对我来说很好,我尝试删除 thread2 和 thread3 中的 mutex_lock DoneMutex,它仍然可以正常工作,我很好奇的是,如果 thread2 正在执行 __sync_add_and_fetch(&iGlbBOOKReadDone,1) ,并且 thread3 正在执行 __sync_add_and_fetch(&iGlbPOSIReadDone, 1) 在完全相同的时间,那么两个线程都会将 if( (iGlbBOOKReadDone == 1) && (iGlbPOSIReadDone == 1) ) 设为 false ,并且永远不会调用 sem_post(semfinished) , 但是我做了很多压力测试,这从来没有发生过!!和__sync_add_and_fetch函数有关系吗?

【问题讨论】:

  • sem_post(semfinished) 可以被调用两次(线程 2 和线程 3 各调用一次)吗?我认为双重发布将是一个错误 - 否则在下一个“回合”中 Thread1 会认为其他线程已立即完成处理。即使使用互斥锁操作,这种竞争条件似乎也存在。如果您的压力测试没有发现该错误,则表明您的压力测试不够充分,或者该错误很少发生(意味着它会在最坏的时间发生)。
  • 感谢您的回复,因为只有 (iGlbBOOKReadDone == 1) && (iGlbPOSIReadDone == 1) 会调用 sem_post(semfinished) ;这意味着 thread2 和 thread3 都完成了动作,即 sem_post(semfinished) ;将唤醒 sem_wait(semfinished) ;在 thread1 中,所以 thread1 会做 DoGetDataFromSocket() ;所以我认为每次thread1获取数据时,thread1唤醒thread2和thread3做工作,然后等待thread2、thread3完成工作并在无限循环中再次唤醒thread1 ....
  • 我认为使用 mutex ,它应该按我的预期工作,我没有得到的是没有 mutex ,它有时应该失败,但它永远不会失败,如果 thread2 看到 iGlbPOSIReadDone = 0 和 thread3 看到 iGlbBOOKReadDone =0 同时,然后 sem_post(semfinished) ;不会被调用,使用 mutex ,这肯定不会发生!

标签: c linux pthreads


【解决方案1】:

正如我在评论中提到的,无论您是否使用互斥锁,您都有一个竞争条件,semfinished 信号量可以被发布两次,这意味着thread1 可能不允许线程在未来完成圆。

很容易看出thread2thread3 可以同时“到达”pthread_mutex_lock() 调用之前的空白行。如果发生这种情况,那么两个线程都会调用sem_post(semfinished)

为了避免这种情况并使代码更易于推理,使您可以确定 thread2thread3 will callsem_post(semfinished) 中的一个,您可能需要考虑执行类似以下:

  • 线程1:

    DoGetDataFromSocket() ;
    threadDoneCount = 0;
    sem_post(sembook) ;
    sem_post(semposi) ;
    sem_wait(semfinished) ;
    
  • 线程2和线程3:

    if(bThisThreadIsBook==1)
        sem_wait(sembook) ;
    else
        sem_wait(semposi) ;
    
    DoPassDatatoAnotherProcess() ;
    
    int doneCount = __sync_add_and_fetch(&threadDoneCount,1) ;
    
    if (doneCount == 2)
        sem_post(semfinished) ;
    

【讨论】:

  • 谢谢你,Burr,你是对的!我错过了一些重要的东西!感谢您的友好解释,它有很大帮助!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多