I want to halt one thread till another thread has finished initializing without using pthread_join. I tried using a join but it leads to a deadlock due to some asynchronous inter-thread communication system that we have. Right now, I'm using a (custom) lock to achieve this.
我想暂停一个线程,直到另一个线程完成初始化而不使用pthread_join。我尝试使用连接,但由于我们拥有一些异步的线程间通信系统,它会导致死锁。现在,我正在使用(自定义)锁来实现这一目标。
In Thread 1:
在线程1中:
lock_OfflineWorker.Lock()
if (pthread_create(&tid0, NULL, RunOfflineWorker, NULL) != 0)
{
}
lock_OfflineWorker.TryLock();
lock_OfflineWorker.Unlock();
In Thread 2:
在线程2中:
bool OfflineWorker::Initialize()
{
lock_OfflineWorker.Unlock();
}
But this is inelegant and I'm not too sure about the side effects (possibility for another deadlock). Is this Ok? If not, is there another way to achieve this (using locks or otherwise)
但这是不优雅的,我不太确定副作用(另一个死锁的可能性)。这个可以吗?如果没有,是否有另一种方法来实现这一点(使用锁或其他)
EDIT: Forgot include the "RunOfflineWorker" function
编辑:忘记包括“RunOfflineWorker”功能
void* RunOfflineWorker(void* pData)
{
g_OfflineWorker.Initialize();
}
2 个解决方案
#1
You can use a pthread condition to wait until the job reaches the wanted state.
您可以使用pthread条件等待作业达到所需状态。
The thread1 waits with pthread_cond_wait()
and the thread2 signals it with pthread_cond_signal()
.
thread1等待pthread_cond_wait(),thread2用pthread_cond_signal()发出信号。
You need :
你需要 :
bool condition ; // or anything else to be tested
pthread_mutex_t mutex ;
pthread_cond_t cond ;
The first thread inits all :
所有的第一个线程:
condition = false ;
pthread_mutex_init( &mutex , PTHREAD_MUTEX_INITIALIZER );
pthread_cond_init( &cond , PTHREAD_COND_INITIALIZER );
Then it waits with the mutex locked. Usually you put the wait in a loop to check the condition whatever it is.
然后等待锁定互斥锁。通常你把等待放在循环中以检查条件是什么。
pthread_mutex_lock( &mutex );
while( ! condition )
{
pthread_cond_wait( &cond , &mutex );
}
pthread_mutex_unlock( &mutex );
The other thread does this when appropriate :
另一个线程在适当时执行此操作:
pthread_mutex_lock( &mutex );
condition = true ; // or false ...
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
#2
I think your solution is just fine, except that you need to use lock_OfflineWorker.Lock()
instead of lock_OfflineWorker.TryLock()
in thread 1 - with TryLock()
, it actually doesn't wait for anything. You cannot use a mutex for that, because it needs to be released by the same thread that locked it, but eg. a semaphore based lock would do. Using a monitor (ie. mutex+condvar) would be just more complex.
我认为你的解决方案很好,除了你需要在线程1中使用lock_OfflineWorker.Lock()而不是lock_OfflineWorker.TryLock() - 使用TryLock(),它实际上不会等待任何事情。你不能使用互斥锁,因为它需要被锁定它的同一个线程释放,但是例如。一个基于信号量的锁会做。使用监视器(即互斥+ condvar)会更复杂。
About deadlocks: Deadlocks are impossible if the initialization part of OfflineWorker (ie. the code before it releases the lock) doesn't wait anywhere. If there are actual deadlocks with your solution, any other solution that makes thread 1 wait for thread 2 would have them too (I can imagine such situation).
关于死锁:如果OfflineWorker的初始化部分(即释放锁之前的代码)不等待任何地方,则死锁是不可能的。如果你的解决方案存在实际的死锁,那么使线程1等待线程2的任何其他解决方案也会有它们(我可以想象这种情况)。
Edit after comment: If you pass messages to thread 1 while it is waiting for the initialization of thread 2 to complete, you have a possibility of deadlock, particularly if there is some bounded buffer for messages or if the message passing function waits for reply. In this situation, I would suggest just abandoning the idea of waiting for thread 2 and maybe pass some callback that would be called from thread 2 when initialization finishes.
注释后编辑:如果在等待线程2的初始化完成时将消息传递给线程1,则可能会出现死锁,特别是如果消息有一些有界缓冲区或者消息传递函数等待回复。在这种情况下,我建议放弃等待线程2的想法,并可能传递一些在初始化完成时从线程2调用的回调。
#1
You can use a pthread condition to wait until the job reaches the wanted state.
您可以使用pthread条件等待作业达到所需状态。
The thread1 waits with pthread_cond_wait()
and the thread2 signals it with pthread_cond_signal()
.
thread1等待pthread_cond_wait(),thread2用pthread_cond_signal()发出信号。
You need :
你需要 :
bool condition ; // or anything else to be tested
pthread_mutex_t mutex ;
pthread_cond_t cond ;
The first thread inits all :
所有的第一个线程:
condition = false ;
pthread_mutex_init( &mutex , PTHREAD_MUTEX_INITIALIZER );
pthread_cond_init( &cond , PTHREAD_COND_INITIALIZER );
Then it waits with the mutex locked. Usually you put the wait in a loop to check the condition whatever it is.
然后等待锁定互斥锁。通常你把等待放在循环中以检查条件是什么。
pthread_mutex_lock( &mutex );
while( ! condition )
{
pthread_cond_wait( &cond , &mutex );
}
pthread_mutex_unlock( &mutex );
The other thread does this when appropriate :
另一个线程在适当时执行此操作:
pthread_mutex_lock( &mutex );
condition = true ; // or false ...
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
#2
I think your solution is just fine, except that you need to use lock_OfflineWorker.Lock()
instead of lock_OfflineWorker.TryLock()
in thread 1 - with TryLock()
, it actually doesn't wait for anything. You cannot use a mutex for that, because it needs to be released by the same thread that locked it, but eg. a semaphore based lock would do. Using a monitor (ie. mutex+condvar) would be just more complex.
我认为你的解决方案很好,除了你需要在线程1中使用lock_OfflineWorker.Lock()而不是lock_OfflineWorker.TryLock() - 使用TryLock(),它实际上不会等待任何事情。你不能使用互斥锁,因为它需要被锁定它的同一个线程释放,但是例如。一个基于信号量的锁会做。使用监视器(即互斥+ condvar)会更复杂。
About deadlocks: Deadlocks are impossible if the initialization part of OfflineWorker (ie. the code before it releases the lock) doesn't wait anywhere. If there are actual deadlocks with your solution, any other solution that makes thread 1 wait for thread 2 would have them too (I can imagine such situation).
关于死锁:如果OfflineWorker的初始化部分(即释放锁之前的代码)不等待任何地方,则死锁是不可能的。如果你的解决方案存在实际的死锁,那么使线程1等待线程2的任何其他解决方案也会有它们(我可以想象这种情况)。
Edit after comment: If you pass messages to thread 1 while it is waiting for the initialization of thread 2 to complete, you have a possibility of deadlock, particularly if there is some bounded buffer for messages or if the message passing function waits for reply. In this situation, I would suggest just abandoning the idea of waiting for thread 2 and maybe pass some callback that would be called from thread 2 when initialization finishes.
注释后编辑:如果在等待线程2的初始化完成时将消息传递给线程1,则可能会出现死锁,特别是如果消息有一些有界缓冲区或者消息传递函数等待回复。在这种情况下,我建议放弃等待线程2的想法,并可能传递一些在初始化完成时从线程2调用的回调。