关于 linux 下 pthread_cond_wait 的原子操作疑问??

hzhxxx 2011-10-21 05:15:57
关于 linux 下 pthread_cond_wait 的原子操作疑问??
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);

int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);

1. pthread_cond_wait 这个函数的主要功能是等待条件变量cond,其实现逻辑是
先把调用线程加入到等待条件变量的列表,然后把解锁mutex,最后阻塞(suspending)调用线程;
2. 当有线程调用 pthread_cond_broadcast(signal) 发送信号后,pthread_cond_wait
解锁再次锁定 mutex,返回给调用线程;

为什么第一步过程中
Unlocking the mutex and suspending on the condition variable is done atomically.
解锁和阻塞要是原子操作???
...全文
288 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq120848369 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 hzhxxx 的回复:]
实际上实现代码看到是先把简要被阻塞线程放入到队列的,再解锁,再阻塞线程;
所以解锁和阻塞不是一个原子操作,应该也能收到的
[/Quote]

看书吧,孩子.
hzhxxx 2011-10-24
  • 打赏
  • 举报
回复


实际上实现代码看到是先把简要被阻塞线程放入到队列的,再解锁,再阻塞线程;
所以解锁和阻塞不是一个原子操作,应该也能收到的
Louistao 2011-10-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 qq120848369 的回复:]

意思是解锁和睡眠是原子的,加锁和唤醒是原子.

如果不原子会有什么问题呢?

解锁和睡眠是原子的:lock --> 检查变量不满足 --> unlock --> sleep

如果变量的改变以及通知事件发生在unlock和sleep中间,那么你不会检测到,也就是错过了这次通知.

加锁和唤醒是原子的:wakeup -- > lock ----> 检查变量是否满足条件.....
……
[/Quote]
求推荐 linux入门书籍
qq120848369 2011-10-21
  • 打赏
  • 举报
回复
意思是解锁和睡眠是原子的,加锁和唤醒是原子.

如果不原子会有什么问题呢?

解锁和睡眠是原子的:lock --> 检查变量不满足 --> unlock --> sleep

如果变量的改变以及通知事件发生在unlock和sleep中间,那么你不会检测到,也就是错过了这次通知.

加锁和唤醒是原子的:wakeup -- > lock ----> 检查变量是否满足条件.....

如果在wakeup之后,在lock之前,其他线程可以修改数据,导致我们Lock后检查的数据可能与我们被唤醒的通知不是一个通知,也就是被1号通知唤醒,却检查了2号通知对变量的改变。

所以,原子性是这样的。
hzhxxx 2011-10-21
  • 打赏
  • 举报
回复


unix 环境高级编程说 可能丢失条件变量变化的通知,但是都已经把调用线程放入到阻塞队列了,应该不会丢失啊...
看了实现代码,还是没有明白

static INLINE int
ptw32_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex, const struct timespec *abstime)
{
int result = 0;
pthread_cond_t cv;
ptw32_cond_wait_cleanup_args_t cleanup_args;

if (cond == NULL || *cond == NULL)
{
return EINVAL;
}

/*
* We do a quick check to see if we need to do more work
* to initialise a static condition variable. We check
* again inside the guarded section of ptw32_cond_check_need_init()
* to avoid race conditions.
*/
if (*cond == PTHREAD_COND_INITIALIZER)
{
result = ptw32_cond_check_need_init (cond);
}

if (result != 0 && result != EBUSY)
{
return result;
}

cv = *cond;

/* Thread can be cancelled in sem_wait() but this is OK */
if (sem_wait (&(cv->semBlockLock)) != 0)
{
return errno;
}

++(cv->nWaitersBlocked);

if (sem_post (&(cv->semBlockLock)) != 0)
{
return errno;
}

/*
* Setup this waiter cleanup handler
*/
cleanup_args.mutexPtr = mutex;
cleanup_args.cv = cv;
cleanup_args.resultPtr = &result;

#ifdef _MSC_VER
#pragma inline_depth(0)
#endif
pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);

/*
* Now we can release 'mutex' and...
*/
if ((result = pthread_mutex_unlock (mutex)) == 0)
{

/*
* ...wait to be awakened by
* pthread_cond_signal, or
* pthread_cond_broadcast, or
* timeout, or
* thread cancellation
*
* Note:
*
* sem_timedwait is a cancellation point,
* hence providing the mechanism for making
* pthread_cond_wait a cancellation point.
* We use the cleanup mechanism to ensure we
* re-lock the mutex and adjust (to)unblock(ed) waiters
* counts if we are cancelled, timed out or signalled.
*/
if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
{
result = errno;
}
}

/*
* Always cleanup
*/
pthread_cleanup_pop (1);
#ifdef _MSC_VER
#pragma inline_depth()
#endif

/*
* "result" can be modified by the cleanup handler.
*/
return result;

} /* ptw32_cond_timedwait */


int
pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a condition variable until
* awakened by a signal or broadcast.
*
* Caller MUST be holding the mutex lock; the
* lock is released and the caller is blocked waiting
* on 'cond'. When 'cond' is signaled, the mutex
* is re-acquired before returning to the caller.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* mutex
* pointer to an instance of pthread_mutex_t
*
*
* DESCRIPTION
* This function waits on a condition variable until
* awakened by a signal or broadcast.
*
* NOTES:
*
* 1) The function must be called with 'mutex' LOCKED
* by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
* the calling thread to block on the condition variable.
* The blocked thread may be awakened by
* pthread_cond_signal or
* pthread_cond_broadcast.
*
* Upon successful completion, the 'mutex' has been locked and
* is owned by the calling thread.
*
*
* RESULTS
* 0 caught condition; mutex released,
* EINVAL 'cond' or 'mutex' is invalid,
* EINVAL different mutexes for concurrent waits,
* EINVAL mutex is not held by the calling thread,
*
* ------------------------------------------------------
*/
{
/*
* The NULL abstime arg means INFINITE waiting.
*/
return (ptw32_cond_timedwait (cond, mutex, NULL));

} /* pthread_cond_wait */


int
pthread_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec *abstime)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a condition variable either until
* awakened by a signal or broadcast; or until the time
* specified by abstime passes.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* mutex
* pointer to an instance of pthread_mutex_t
*
* abstime
* pointer to an instance of (const struct timespec)
*
*
* DESCRIPTION
* This function waits on a condition variable either until
* awakened by a signal or broadcast; or until the time
* specified by abstime passes.
*
* NOTES:
* 1) The function must be called with 'mutex' LOCKED
* by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
* the calling thread to block on the condition variable.
* The blocked thread may be awakened by
* pthread_cond_signal or
* pthread_cond_broadcast.
*
*
* RESULTS
* 0 caught condition; mutex released,
* EINVAL 'cond', 'mutex', or abstime is invalid,
* EINVAL different mutexes for concurrent waits,
* EINVAL mutex is not held by the calling thread,
* ETIMEDOUT abstime ellapsed before cond was signaled.
*
* ------------------------------------------------------
*/
{
if (abstime == NULL)
{
return EINVAL;
}

return (ptw32_cond_timedwait (cond, mutex, abstime));

} /* pthread_cond_timedwait */
hzhxxx 2011-10-21
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 demon__hunter 的回复:]
防止解锁或阻塞的操作中发生线程切换,原子操作不会被线程切换中断
[/Quote]

就算切换有应该没有问题啊。解锁后,其他线程能获取到锁??


不原子有什么后果,有反例吗?
机智的呆呆 2011-10-21
  • 打赏
  • 举报
回复
防止解锁或阻塞的操作中发生线程切换,原子操作不会被线程切换中断

64,701

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧