我有一个在Linux内核2.6.18-194中运行的c程序,服务器有一个带6核的超线程cpu套接字,线程1接收数据,然后线程2和线程3将线程1接收的数据传递给另一个进程,在线程2和螺纹3成功完成数据传递后,线程1将再次接收数据!!
洪水泛滥1来源:
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) ;
它对我来说很好,我试图在线程2和线程3中删除互斥锁DoneMutex,它仍然很好,但我很好奇的是,如果线程2正在执行__sync_add_and_fetch(&iGlbBOOKReadDone,1),而线程3正在执行__sync_add_aand_fetch则两个线程都将执行if((iGlbBOOKReadDone==1)&;(iGlbPOSIReadDone==1))为false并且sem_post(semfinished)将永远不会被调用,但我做了很多压力测试,这从来没有发生过!!是否与__sync_add_and_fetch函数有关?
正如我的评论中所提到的,无论您是否使用互斥,您都有一个竞争条件,即semfinished
信号量可以发布两次,这意味着thread1
可能不允许线程在未来一轮中完成。
很容易看出,thread2
和thread3
都可以同时"到达"pthread_mutex_lock()
调用之前的空白行。如果发生这种情况,那么两个线程都将调用sem_post(semfinished)
。
为了避免这种情况,并使代码更容易推理,使其能够确定thread2
和thread3 will call
中的某一个sem_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) ;