问使用 posix 条件变量的问题

zhoufanking 2008-06-24 02:38:39
先贴一段代码:
1> pthread_mutex_t count_lock;
2> pthread_cond_t count_nonzero;
3> unsigned count;
4>
5> decrement_count()
6> {
7> pthread_mutex_lock(&count_lock);
8> while (count == 0)
9> pthread_cond_wait(&count_nonzero, &count_lock);
10> count = count - 1;
11> pthread_mutex_unlock(&count_lock);
12> }

问题:1.当线程阻塞在cond_wait后,如果这时收到了cond_signal,它的状态即变为就绪态,等到CPU资源后就可以向下执行,并不是接收到signal后立即转为执行。其它线程也有可能先于它被唤醒,对count进行操作。这样理解对吗?
2.关于阻塞在cond_wait的线程,接收到cond_signal并且分到CPU后的执行顺序:
它是返回到第7行加锁,然后再执行第8行判断count是否为零呢,还是在cond_wait中自动完成加锁及判断条件?我试着在第8行和第9行之间加了一条print语句,线程被唤醒后并没有再次执行这条语句,说明再次锁mutex和条件判断是cond_wait自动完成的,那他是怎么知道判断条件的呢?
...全文
117 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
tanglaoya0001 2008-06-25
  • 打赏
  • 举报
回复
PThreads Primer 一书中这样描述的:
?
lock-> cond -----> continue unlock
^ |
| |-------> unlock sleep lock -> |
| ^ |
---------------------|-----------|
|
|
|
lock-> cond = TRUE -> unlock ->wakeup -> continue

但我在RedHat 9.0 上测试了一下,感觉不像,不知道在其他平台上是什么样的,

大家可以在其他平台上测试 然后分享下结果。
tanglaoya0001 2008-06-25
  • 打赏
  • 举报
回复
Linux 下我认为是这样的:
pthread_mutex_lock(&count_lock); // count_lock 锁住

pthread_cond_wait(&count_nonzero, &count_lock); // 如果没有收到信号线程进入阻塞队列,该线程对count_lock解锁(内部实现)并进入Sleep状态,当收到signal信号后,对count_lock加锁,然后继续向后执行

pthread_mutex_unlock(&count_lock); // 解锁

在RedHat 9.0下面是这样的。而且当调用signal时,如果此时对条件变量count_nonzero阻塞的队列是空的,发送的信号还会丢失。
AlxRose 2008-06-25
  • 打赏
  • 举报
回复
如果cond_wait都还没来得及执行,他怎么自动加锁呢?如果先于它被调度的一个线程锁了count并对其操作,count值在cond_wait醒来时不就被改变了吗?

我感觉你好像搞混了,在cond_wait之前count_lock已经锁住了:

在line7,line9(开区间)之间,count_lock是被锁住了的,其他线程拿不到这把锁也就改不了count
在line9 pthread_cond_wait执行期间, count_lock被解锁了,其他线程可以改变count
line9 pthread_cond_wait返回后,count_lock继续被锁,其他线程拿不到锁改不了count
windowsxp0925 2008-06-25
  • 打赏
  • 举报
回复
8> while (count == 0)
9> pthread_cond_wait(&count_nonzero, &count_lock);

上面的代码执行循序是:
先判断count == 0,如果为真,则执行pthread_cond_wait(),pthread_cond_wait()是一个阻塞的函数,直到pthread_cond_signal()来唤醒它。唤醒了之后这段代码就执行完了一次,此后就从头再来,继续判断,然后阻塞等待 。

我不知道这么说你明白没有。


BTW:顺便说一下昨天的一个 问题:
其它线程也有可能先于它被唤醒,对count进行操作。[不确定,好像现在的系统里已经屏蔽掉了“惊群”现象]

我刚才看了一下man pthread_cond_signal
DESCRIPTION
These functions shall unblock threads blocked on a condition variable.

The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).

If more than one thread is blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked. When each thread unblocked as a result of a pthread_cond_broadcast() or pthread_cond_signal() returns from its call to pthread_cond_wait() or pthread_cond_timedwait(), the thread shall own the mutex with which it called pthread_cond_wait() or pthread_cond_timedwait(). The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if appli cable), and as if each had called pthread_mutex_lock().

The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().

The pthread_cond_broadcast() and pthread_cond_signal() functions shall have no effect if there are no threads currently blocked on cond.


红色标识就是所谓惊群现象。
蓝色标识就是说明多个线程被唤醒后调度的策略。
zhoufanking 2008-06-25
  • 打赏
  • 举报
回复
to:AlxRose
如果cond_wait都还没来得及执行,他怎么自动加锁呢?如果先于它被调度的一个线程锁了count并对其操作,count值在cond_wait醒来时不就被改变了吗?
to:windowsxp0925
2.我指的判断条件:count==0
zhoufanking 2008-06-25
  • 打赏
  • 举报
回复
贴我的一段测试代码,我的目的是cnt==10时唤醒watcher,结果watcher醒来后检查cnt已经不一定是10了,代码后面是我机子上的运行结果。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define THREAD_NUM 3
#define CONDITION 10
#define TCOUNT 6

static int cnt;
pthread_t td[THREAD_NUM];
pthread_mutex_t mutex;
pthread_cond_t cond;


void *inc_count( void *args)
{

int *myid = (int *) args;
int idx;

sleep(1);
for( idx = 0; idx < TCOUNT ; idx++)
{
pthread_mutex_lock(&mutex);
cnt++;

if(cnt == CONDITION)
{
pthread_cond_signal(&cond);
printf("inc_count():thread %d, cnt=%d sending condition signal!\n",*myid,cnt);
}
pthread_mutex_unlock(&mutex);
printf("inc_count():thread %d, cnt=%d unlock mutexl!\n",*myid,cnt);
}
pthread_exit((void *) 0);
}

void *watcher(void *args)
{
int *myid = (int *)args;
printf("watcher(): thread %d, waiting for signal!\n",*myid);

pthread_mutex_lock(&mutex);
if(cnt < CONDITION)
{
printf("watcher():ready to wait signal\n");
pthread_cond_wait(&cond,&mutex);
printf("watcher():signal received! cnt=%d.\n",cnt);
}

pthread_mutex_unlock(&mutex);

pthread_exit( (void *) 0);
}

int thread_ids[] = {1,2,3};

int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
int i;
pthread_create(&td[0],NULL,inc_count,(void *)&thread_ids[0]);
pthread_create(&td[1],NULL,inc_count,(void *)&thread_ids[1]);
pthread_create(&td[2],NULL,watcher,(void *)&thread_ids[2]);

for(i=0; i< THREAD_NUM; i++)
{
pthread_join(td[i],NULL);
}
printf("main():waited on %d threads. Done.\n",THREAD_NUM);

pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);

pthread_exit(NULL);
}
/***************************res.txt***********************/
watcher(): thread 3, waiting for signal!
watcher():ready to wait signal
inc_count():thread 1, cnt=1 unlock mutexl!
inc_count():thread 1, cnt=2 unlock mutexl!
inc_count():thread 1, cnt=3 unlock mutexl!
inc_count():thread 1, cnt=4 unlock mutexl!
inc_count():thread 1, cnt=5 unlock mutexl!
inc_count():thread 1, cnt=6 unlock mutexl!
inc_count():thread 2, cnt=7 unlock mutexl!
inc_count():thread 2, cnt=8 unlock mutexl!
inc_count():thread 2, cnt=9 unlock mutexl!
inc_count():thread 2, cnt=10 sending condition signal!
inc_count():thread 2, cnt=10 unlock mutexl!
inc_count():thread 2, cnt=11 unlock mutexl!
inc_count():thread 2, cnt=12 unlock mutexl!
watcher():signal received! cnt=12.
main():waited on 3 threads. Done.
/***************************************************************/
如果上面的代码没什么问题的话,那么阻塞在cond_wait上的线程收到cond_signal并被唤醒前,其他线程是可能被调度并修改cnt的。如果在watcher中用while判断而不是if的话(红色那行),watcher可能永远醒不来。
偶像罗斯福 2008-06-24
  • 打赏
  • 举报
回复
mark
windowsxp0925 2008-06-24
  • 打赏
  • 举报
回复
[Quote=引用楼主 zhoufanking 的帖子:]
先贴一段代码:
1> pthread_mutex_t count_lock;
2> pthread_cond_t count_nonzero;
3> unsigned count;
4>
5> decrement_count()
6> {
7> pthread_mutex_lock(&count_lock);
8> while (count == 0)
9> pthread_cond_wait(&count_nonzero, &count_lock);
10> count = count - 1;
11> pthread_mutex_unlock(&count_lock);
12> }

问题:1.当线程阻塞在cond_wait后,如果这时收到了cond_signal,…
[/Quote]


1:
1.当线程阻塞在cond_wait后,如果这时收到了cond_signal,它的状态即变为就绪态,等到CPU资源后就可以向下执行,并不是接收到signal后立即转为执行。 [理解OK]
其它线程也有可能先于它被唤醒,对count进行操作。[不确定,好像现在的系统里已经屏蔽掉了“惊群”现象]

2:
.关于阻塞在cond_wait的线程,接收到cond_signal并且分到CPU后的执行顺序:
是在cond_wait中自动完成加锁及判断条件
那他是怎么知道判断条件的呢?你这里的判断条件是指什么?
AlxRose 2008-06-24
  • 打赏
  • 举报
回复
pthread_cond_wait执行时,count_lock解锁,pthread_cond_wait返回前再自动加锁,所以描述1不可能,除非某处操作count前没有锁count_lock

23,116

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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