在pthreads中失去了醒来

时间:2014-03-15 17:48:01

标签: c pthreads

我已经编写了一些程序来尝试pthread条件等待。 但问题是,不能保证发出的信号会被捕获,从而线程失去唤醒。我该如何解决这个问题?

#include<stdio.h>
#include<pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_func1(void* arg){
  printf("thread1 started\n");
  pthread_mutex_lock(&mutex);
  printf("thread1: signalling\n");
  pthread_cond_signal(&cond);
  printf("thread1: signalled\n");
  pthread_mutex_unlock(&mutex);
  printf("thread1: exiting\n");
  pthread_exit(0);
}

void *thread_func2(void* arg){
  printf("thread2 started\n");
  pthread_mutex_lock(&mutex);
  printf("thread2: waiting for signal..\n");
  pthread_cond_wait(&cond, &mutex);
  printf("thread2: signal received\n");
  pthread_mutex_unlock(&mutex);
  printf("thread2: exiting\n");
  pthread_exit(0);
}

int main(int argc, char** argv){
  pthread_t thread1, thread2;

  pthread_create(&thread1, NULL, thread_func1, NULL);
  pthread_create(&thread2, NULL, thread_func2, NULL);

  pthread_join(thread1, 0);
  pthread_join(thread2, 0);

  return 0;
}

以下是run:

的输出
thread1 started
thread1: signalling
thread2 started
thread2: waiting for signal..
thread1: signalled
thread1: exiting
// nothing happens now; where is the signal??

这是另一个(有效):

thread2 started
thread2: waiting for signal..
thread1 started
thread1: signalling
thread1: signalled
thread1: exiting
thread2: signal received
thread2: exiting
// program successfully exits

我现在不关心任何关键部分,所以我没有使用任何锁。

如何确保每次运行都能正常运行?

编辑:我根据下面的答案编辑了代码。我添加了初始化器和锁。我发布的原始代码是here

2 个答案:

答案 0 :(得分:2)

正如您所注意到的,线程1可能会在线程2调用pthread_cond_wait()之前发出条件变量的信号。条件变量不记得&#34;已经发出信号,所以唤醒将会丢失。因此,您需要使用某种变量来确定线程2是否需要等待。

int signalled = 0;

void *thread_func1(void* arg){
  printf("thread1 started\n");
  pthread_mutex_lock(&mutex);
  printf("thread1: signalling\n");
  signalled = 1;
  pthread_cond_signal(&cond);
  printf("thread1: signalled\n");
  pthread_mutex_unlock(&mutex);
  printf("thread1: exiting\n");
  pthread_exit(0);
}

void *thread_func2(void* arg){
  printf("thread2 started\n");
  pthread_mutex_lock(&mutex);
  printf("thread2: waiting for signal..\n");
  if(!signalled) {
    pthread_cond_wait(&cond, &mutex);
  }
  printf("thread2: signal received\n");
  pthread_mutex_unlock(&mutex);
  printf("thread2: exiting\n");
  pthread_exit(0);
}

但是,此代码仍然不正确。 pthreads规范表明&#34;虚假的唤醒&#34;可能在条件变量上发生。这意味着即使没有人调用pthread_cond_wait()pthread_cond_signal()pthread_cond_broadcast()也可能会返回。因此,您需要在循环中检查标志,而不是仅检查一次:

void *thread_func2(void* arg){
  printf("thread2 started\n");
  pthread_mutex_lock(&mutex);
  printf("thread2: waiting for signal..\n");
  while(!signalled) {
    pthread_cond_wait(&cond, &mutex);
  }
  printf("thread2: signal received\n");
  pthread_mutex_unlock(&mutex);
  printf("thread2: exiting\n");
  pthread_exit(0);
}

更新:组合条件变量和计数器功能的另一种方法是使用信号量。

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t sem;

void *thread_func1(void* arg){
  printf("thread1 started\n");
  printf("thread1: signalling\n");
  sem_post(&sem);
  printf("thread1: signalled\n");
  printf("thread1: exiting\n");
  pthread_exit(0);
}

void *thread_func2(void* arg){
  printf("thread2 started\n");
  printf("thread2: waiting for signal..\n");
  sem_wait(&sem);
  printf("thread2: signal received\n");
  printf("thread2: exiting\n");
  pthread_exit(0);
}

int main(int argc, char** argv){
  pthread_t thread1, thread2;

  sem_init(&sem);

  pthread_create(&thread1, NULL, thread_func1, NULL);
  pthread_create(&thread2, NULL, thread_func2, NULL);

  pthread_join(thread1, 0);
  pthread_join(thread2, 0);

  sem_destroy(&sem);

  return 0;
}

答案 1 :(得分:0)

对于初学者,您的代码会错过初始化mutexcond

为此,至少要这样做:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

传递给pthread_cond_wait()的互斥锁也应 锁定。当函数返回时 被锁定。


更新

您的代码介绍了一场比赛。也就是说:如果线程1在线程2等待信号之前发出信号,则线程2将永远等待,这很可能发生在您显示的第一条跟踪中。