【问题标题】:how to avoid polling in pthreads如何避免在 pthread 中进行轮询
【发布时间】:2011-06-05 14:16:10
【问题描述】:

我有一些目前看起来像这样的代码(简化)

/* instance in global var *mystruct, count initialized to 0 */
typedef struct {
    volatile unsigned int count;
} mystruct_t;

pthread_mutex_t mymutex; // is initialized

/* one thread, goal: block while mystruct->count == 0 */
void x(void *n) {
    while(1) {
        pthread_mutex_lock(&mymutex);
        if(mystruct->count != 0) break;
        pthread_mutex_unlock(&mymutex);       
    }
    pthread_mutex_unlock(&mymutex);
    printf("count no longer equals zero");
    pthread_exit((void*) 0)
}

/* another thread */
void y(void *n) {
    sleep(10);
    pthread_mutex_lock(&mymutex);
    mystruct->count = 10;
    pthread_mutex_unlock(&mymutex);
}

这对我来说似乎效率低下且错误——但我不知道更好的方法。有没有更好的方法,如果有,是什么?

【问题讨论】:

  • 建议在break退出while循环后解锁互斥锁。
  • 或者,如果你很懒惰,你可以使用强大的互斥锁并让pthread_exit“解锁”它...

标签: c multithreading pthreads posix


【解决方案1】:

条件变量允许您等待某个事件,并有一个不同的线程信号该条件变量。

你可以有一个线程来做这个:

for (;;)
{
   if (avail() > 0)
      do_work();
   else
      pthread_cond_wait();
}

以及执行此操作的不同线程:

for (;;)
{
   put_work();
   pthread_cond_signal();
}

当然非常简单。 :) 您需要了解如何正确使用它,由于竞争条件,使用条件变量会遇到一些困难。

但是,如果您确定线程会阻塞很短的时间(以 µs 为单位)并且很少发生,那么使用这样的自旋循环可能会更有效。

【讨论】:

  • +1 我喜欢障碍,但条件变量几乎肯定是这里任务的正确工具,因为没有迹象表明条件的“生产者”应该阻塞,直到条件的“消费者”准备好处理它。
  • 当没有匹配的pthread_cond_wait(...) 时,pthread_cond_signal(...) 会发生什么?
  • 没什么,它被忽略了。相反,pthread_cond_wait 没有pthread_cond_signal 会导致线程无限期等待。
【解决方案2】:

一般的解决方案是使用 POSIX 信号量。这些不是 pthread 库的一部分,但可以与 pthread 一起使用。

由于大多数其他多线程 API 中都提供了信号量,因此它是一种通用技术,可能更易于应用;然而,在这种情况下也许更合适的是 condition variable,它允许线程在不轮询的情况下挂起变量的条件值,这似乎 正是想要。

【讨论】:

    【解决方案3】:

    条件变量是解决这个问题的方法。您的代码可以很容易地修改以使用它们:

    pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
    
    /* one thread, goal: block while mystruct->count == 0 */
    void x(void *n) {
        pthread_mutex_lock(&mymutex);
        while (mystruct->count == 0)
            pthread_cond_wait(&mycond, &mymutex);
    
        printf("count no longer equals zero");
        pthread_mutex_unlock(&mymutex);
    
        pthread_exit((void*) 0)
    }
    
    /* another thread */
    void y(void *n) {
        sleep(10);
        pthread_mutex_lock(&mymutex);
        mystruct->count = 10;
        pthread_cond_signal(&mycond);
        pthread_mutex_unlock(&mymutex);
    }
    

    请注意,在对结果进行操作时,您通常应该保持互斥锁锁定 - “使用”事件或类似事件。这就是我将pthread_mutex_unlock() 移到printf() 之后的原因,即使在这个玩具箱中它并不重要。

    (另外,在实际代码中,将互斥锁和条件变量放在mystruct 中可能很有意义。

    【讨论】:

      【解决方案4】:

      你可以使用barriers

      【讨论】:

        【解决方案5】:

        您也可以使用semaphores 来同步线程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-05
          • 1970-01-01
          • 2020-08-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多