条件变量的实现

时间:2012-06-12 16:22:22

标签: c linux multithreading gcc pthreads

为了理解pthread条件变量的代码,我编写了自己的版本。它看起来是否正确?我在一个程序中使用它,它的工作,但工作速度惊人得多。最初程序大约需要2.5秒,使用我的条件变量版本只需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));
}

3 个答案:

答案 0 :(得分:4)

除了缺少返回值检查之外,还有一些问题需要解决:

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

进一步评论:

  • 省略的销毁操作可能需要更改其他操作,因此当POSIX认为它是安全的时,可以安全地销毁条件变量。不支持销毁或对可能被调用的时间施加更严格的限制将简化事情。
  • 生产实现将处理线程取消。
  • 退出等待(例如线程取消和pthread_cond_timedwait超时所需)可能会导致并发症。
  • 您的实现将用户空间中的线程排队,这是出于性能原因在某些生产实现中完成的;我不明白为什么。
  • 您的实现始终以LIFO顺序对线程进行排队。这通常更快(例如由于缓存效应)但可能导致饥饿。生产实施有时可能会使用FIFO订单来避免饥饿。

答案 1 :(得分:2)

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

  • 您没有检查POSIX函数的返回值。特别是sem_wait是可以中断的,所以在重负载或运气不好的情况下,你的线程会被虚假地唤醒。你必须小心翼翼地抓住所有这些
  • 您的所有函数都不会返回值。如果某些函数的用户某天决定使用返回值,则这是未定义的行为。仔细分析允许条件函数返回的错误代码并执行此操作。
  • 不会转发malloccalloc
  • 的回复

修改:实际上,您根本不需要malloc / free。一个局部变量也可以。

答案 2 :(得分:2)

您似乎不尊重此要求:

  

这些函数以原子方式释放互斥锁并导致调用线程阻塞条件变量cond;这里原子意味着   “原子地关于另一个线程访问互斥锁然后条件变量”。也就是说,如果另一个线程能够获取互斥锁   在即将发布的线程发布之后,在该线程中对pthread_cond_broadcast()或pthread_cond_signal()的后续调用将   表现就好像是在约会阻止线程被阻止之后发布的。

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

P.S。我不确定自己是否正确地解释了这一段,请随意指出我的错误。