Guaranteed yielding with pthread_cond_wait and pth

2019-07-08 09:53发布

问题:

Assuming I have a C program with 3 POSIX threads, sharing a global variable, mutex, and condition variable, two of which are executing the following psuedocode:

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

And the third running:

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

Is it safe to assume that the third thread will see the data from each of the first two?

Put a different way, if a thread is wating on a mutex and a condition variable, is it safe to assume that it will be the next one to get the lock if it is signaled, rather than some other thread that may be waiting on the lock?

回答1:

There's no such thing as pthread_mutex_wait. I assume you mean:

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

There is no guarentee that the third thread will see the data from both. pthread_cond_signal will awaken the third thread, but it may not take the mutex immediately. One of the other writers may take the mutex first. However you can acheive what you want with a bit more work:

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;
}

By explicitly waiting for the variable to be read, we avoid the potential race condition.



回答2:

Here is what I found in the standard:

4.13 Scheduling Policy

A scheduling policy affects process or thread ordering:

[...]

  • When a process or thread is a blocked thread and it becomes a runnable thread

Conforming implementations shall define the manner in which each of the scheduling policies may modify the priorities or otherwise affect the ordering of processes or threads at each of the occurrences listed above. Additionally, conforming implementations shall define in what other circumstances and in what manner each scheduling policy may modify the priorities or affect the ordering of processes or threads.

So it's apparently undefined. It's not surprising: generally speaking, you can't assume anything about which runnable thread will be scheduled to run.



回答3:

According to the pthread_cond_wait manpage

The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock().

Unfortunately as far as I can tell, there is no available scheduling policy that gives you the behavior you want.