【发布时间】: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 ,这肯定不会发生!