2

假设我有一个具有 3 个 POSIX 线程的 C 程序,共享一个全局变量、互斥体和条件变量,其中两个正在执行以下伪代码:

...process data...
pthread_mutex_lock( &mutex );
variable = data_ptr;
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );

第三次运行:

while(1) {
    while( variable == NULL ) {
        pthread_mutex_wait( &cond, &mutex );
    }
    printf( "Data is %d", *variable );
}

假设第三个线程将看到前两个线程的数据是否安全?

换一种说法,如果一个线程正在等待一个互斥锁和一个条件变量,是否可以安全地假设如果发出信号,它将是下一个获得锁的线程,而不是可能正在等待的其他线程锁?

4

3 回答 3

12

没有 pthread_mutex_wait 这样的东西。我假设你的意思是:

pthread_mutex_lock(&mutex);
/* ... */
while (1) {
  while (variable == NULL)
    pthread_cond_wait(&cond, &mutex);
  printf("Data is %d", *variable);
}
/* ... */
pthread_mutex_unlock(&mutex);

不能保证第三个线程会看到两者的数据。pthread_cond_signal 将唤醒第三个线程,但它可能不会立即获取互斥锁。其他作者之一可能会先使用互斥锁。但是,您可以通过更多的工作来实现您想要的:

void put(int *p) {
  pthread_mutex_lock(&mutex);
  while (variable)
    pthread_cond_wait(&cond_empty, &mutex);
  variable = p;
  pthread_cond_signal(&cond_full);
  pthread_mutex_unlock(&mutex);
}

int *get() {
  int *ret;

  pthread_mutex_lock(&mutex);
  while (!variable)
    pthread_cond_wait(&cond_full, &mutex);
  ret = variable;
  variable = NULL;
  pthread_cond_signal(&cond_empty);
  pthread_mutex_unlock(&mutex);

  return ret;
}

通过显式等待变量被读取,我们避免了潜在的竞争条件。

于 2009-08-03T15:11:23.547 回答
1

这是我在标准中发现的:

4.13 调度策略

调度策略会影响进程或线程的顺序:

[...]

  • 当一个进程或线程是一个阻塞线程并且它变成一个可运行线程时

一致的实现应定义每个调度策略可以修改优先级或以其他方式影响上面列出的每个事件的进程或线程的顺序的方式。此外,符合要求的实现应定义在哪些其他情况下以及每个调度策略可以以何种方式修改优先级或影响进程或线程的顺序。

所以它显然是未定义的。这并不奇怪:一般来说,您不能假设将安排运行哪个可运行线程。

于 2009-08-03T15:12:57.477 回答
0

根据pthread_cond_wait手册页

未阻塞的线程应根据调度策略(如果适用)竞争互斥锁,就好像每个线程都调用了pthread_mutex_lock()。

不幸的是,据我所知,没有可用的调度策略可以为您提供所需的行为。

于 2009-08-03T15:13:03.077 回答