我发现了以下主题(这里关于pthreads但有很多好的解决方案。
我想知道以下代码是否有效,如果是,为什么使用相同的锁来调用pthread_cond_wait以及访问它然后立即解锁:
void suspendMe()
{
pthread_mutex_lock(&m_SuspendMutex);
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
pthread_mutex_unlock(&m_SuspendMutex);
}
在这里使用2个独立的互斥量不是更好吗,或者这是暂停pthread的正确方法?
提前致谢!
编辑:
很棒的回复,谢谢大家。
还有一个相关的问题。既然我想在另一个函数中单独恢复一个线程,那么恢复它会更合适吗?
void suspendMe()
{
pthread_mutex_lock(&m_SuspendMutex);
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
pthread_cond_signal(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
再次感谢大家! :〜)
实际上,这段代码不是线程安全的。互斥体实际上并没有保护任何东西,使隐含的谓词容易受到竞争条件的影响。
看看这段代码 - 互斥保护是什么?什么保护暂停/恢复状态?
void suspendMe()
{
pthread_mutex_lock(&m_SuspendMutex);
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
pthread_cond_signal(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
这是对的:
void suspendMe()
{ // tell the thread to suspend
pthread_mutex_lock(&m_SuspendMutex);
m_SuspendFlag = 1;
pthread_mutex_unlock(&m_SuspendMutex);
}
void resumeMe()
{ // tell the thread to resume
pthread_mutex_lock(&m_SuspendMutex);
m_SuspendFlag = 0;
phtread_cond_broadcast(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
void checkSuspend()
{ // if suspended, suspend until resumed
pthread_mutex_lock(&m_SuspendMutex);
while (m_SuspendFlag != 0) pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
pthread_mutex_unlock(&m_SuspendMutex);
}
线程应该调用 checkSuspend
在可以暂停的安全点。其他线程可以调用 suspendMe
和 resumeMe
暂停/恢复线程。
请注意,现在互斥锁可以保护 m_SuspendFlag
变量,确保线程被告知暂停,告知恢复,并检查它是否应该暂停或保持暂停状态,使代码线程安全。
在这里使用2个独立的互斥量不是更好吗,或者这是暂停pthread的正确方法?
使用两个互斥量会破坏条件变量的整个点。它们工作的整个机制是你可以检查是否有你应该等待的东西,然后在你等待或不得不释放锁然后等待时,无需持有锁定就可以原子地等待它。如果在等待时按住锁定,其他任何线程如何改变状态?如果您释放锁定然后等待,如果您错过了状态更改会发生什么?
顺便说一句,暂停或恢复一个线程几乎没有意义。如果您觉得需要从外部暂停一个线程,那只表示您编写了线程以执行您实际上不希望它执行的操作。关于暂停或恢复线程的问题通常表明线程编程的心理模型不正确。一个线程可能需要等待某些东西,但它不应该从外部“暂停”,因为它应该已经知道它自己的编码什么时候它不应该做一些特定的工作。
这是正确的方法。 pthread_cond_wait
解锁 m_SuspendMutex
然后等待 m_ResumeCond
然后锁定 m_SuspendMutex
再回来之前。
它以这种方式工作的原因是因为条件变量用于表示某个状态的变化,并且由于该状态是共享的,因此必须在某个线程访问它时锁定它。例如。考虑实现一个事件队列:
T get_item()
{
pthread_mutex_lock(&mutex);
while(qu.empty())
pthread_cond_wait(&cond, &mutex);
T ret = qu.front();
qu.pop();
pthread_mutex_unlock(&mutex);
return ret; // we got an item from a queue
}
void add_item(T x)
{
pthread_mutex_lock(&mutex);
qu.push(x);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
注意:
- 所有对队列的访问权限
qu
是使用同步 mutex
。
- 当我们等待条件变量时,我们必须解锁
mutex
为了允许其他线程将项添加到队列中,并且当它被更改时我们必须锁定 mutex
再次实际检查队列。这正是如此 pthread_cond_signal
确实。
我想知道以下代码是否有效
是。
如果是这样,为什么使用相同的锁来调用pthread_cond_wait以及访问它然后立即解锁:
该 pthread_cond_wait()
需要一个锁定的互斥锁。这是因为使用条件变量的方式。通常它们使用如下:
pthread_mutex_lock(&m_SuspendMutex);
while (!ready())
{
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
// Modify the resources protexted by the lock.
pthread_mutex_unlock(&m_SuspendMutex);
因此,您获得锁定,表示您要修改受锁定保护的资源。但如果对象不在 ready()
然后你暂停你的线程 pthread_cond_wait()
它挂起线程并解锁互斥锁(从而允许其他线程获取锁并可能将对象转换为 ready()
州)。
当达到就绪状态时 m_ResumeCond
发出信号并暂停等待线程。但在被允许退出之前 pthread_cond_wait()
它必须重新获得锁定 m_SuspendMutex
确保它是修改受互斥锁保护的资源的唯一线程。
要确保以原子方式正确完成上述操作(解锁/暂停/恢复/锁定)必须完成 pthread_cond_wait()
。
在这里使用2个独立的互斥体会不会更好
没有。
或者这是暂停pthread的正确方法?
和其他任何我想的一样好。