条件variables的实现

为了理解pthread条件variables的代码,我写了自己的版本。 它看起来正确吗? 我正在使用它在一个程序,它的工作,但工作惊人的快得多。 程序本来需要大约2.5秒,而我的版本的条件variables只需要0.8秒,程序的输出也是正确的。 但是,我不确定,如果我的执行是正确的。

struct cond_node_t { sem_t s; cond_node_t * next; }; struct cond_t { cond_node_t * q; // Linked List pthread_mutex_t qm; // Lock for the Linked List }; int my_pthread_cond_init( cond_t * cond ) { cond->q = NULL; pthread_mutex_init( &(cond->qm), NULL ); } int my_pthread_cond_wait( cond_t* cond, pthread_mutex_t* mutex ) { cond_node_t * self; pthread_mutex_lock(&(cond->qm)); self = (cond_node_t*)calloc( 1, sizeof(cond_node_t) ); self->next = cond->q; cond->q = self; sem_init( &self->s, 0, 0 ); pthread_mutex_unlock(&(cond->qm)); pthread_mutex_unlock(mutex); sem_wait( &self->s ); free( self ); // Free the node pthread_mutex_lock(mutex); } int my_pthread_cond_signal( cond_t * cond ) { pthread_mutex_lock(&(cond->qm)); if (cond->q != NULL) { sem_post(&(cond->q->s)); cond->q = cond->q->next; } pthread_mutex_unlock(&(cond->qm)); } int my_pthread_cond_broadcast( cond_t * cond ) { pthread_mutex_lock(&(cond->qm)); while ( cond->q != NULL) { sem_post( &(cond->q->s) ); cond->q = cond->q->next; } pthread_mutex_unlock(&(cond->qm)); } 

基本上你的策略看起来不错,但你有一个主要的危险,一些未定义的行为,并挑选一个挑战:

  • 你没有检查你的POSIX函数的返回值。 特别是sem_wait是可以中断的,所以在重载或运气不好的情况下,你的线程将被虚假地唤醒。 你必须小心翼翼地抓住这一切
  • 没有你的函数返回一个值。 如果某些函数的用户有一天会决定使用返回值,这是未定义的行为。 仔细分析条件函数允许返回的错误代码,并做到这一点。
  • 不要投入malloccalloc的返回

编辑:其实,你根本不需要malloc / free 。 局部变量也可以。

除了缺少返回值检查之外,还有一些问题应该可以解决:

  • sem_destroy不被调用。
  • 信号/广播在唤醒目标线程之后触摸cond_node_t ,可能导致免费使用。

进一步评论:

  • 省略的销毁操作可能需要对其他操作进行更改,因此在POSIX表示应该是安全的情况下销毁条件变量是安全的。 不支持销毁或强制限制什么时候可以被调用将简化事情。
  • 生产实现将处理线程取消。
  • 退出等待(如线程取消和pthread_cond_timedwait超时所需)可能会导致并发症。
  • 你的实现队列在userland中的线程,这是出于性能原因在一些生产实现中完成的; 我不明白为什么。
  • 您的实现总是以LIFO顺序排队。 这通常更快(例如由于缓存效应),但可能导致饥饿。 生产实施有时可能使用先进先出顺序来避免饥饿。

你似乎不尊重这个要求:

这些函数以原子方式释放互斥并导致调用线程在条件变量cond上阻塞; 原子地这里的意思是“原子地相对于另一个线程访问互斥体,然后是条件变量”。 也就是说,如果另一个线程能够在约程序线程释放它之后获取该互斥体,则该线程中的pthread_cond_broadcast()或pthread_cond_signal()的后续调用应该如同在about-阻塞线程被阻塞。

你解锁,然后等待。 另一个线程可以在这些操作之间做很多事情。

PS我不确定自己,如果我正确地解释这一段,随时指出我的错误。