0

下面的代码取自关于 pthreads 的 llnl 教程,有两个修改:

  1. 注释sleep(1);in 函数
  2. 注释 pthread_join(thread[i],NULL);in 函数 main

    /******************************************************************************
    * FILE: condvar.c
    * DESCRIPTION:
    *   Example code for using Pthreads condition variables.  The main thread
    *   creates three threads.  Two of those threads increment a "count" variable,
    *   while the third thread watches the value of "count".  When "count" 
    *   reaches a predefined limit, the waiting thread is signaled by one of the
    *   incrementing threads. The waiting thread "awakens" and then modifies
    *   count. The program continues until the incrementing threads reach
    *   TCOUNT. The main program prints the final value of count.
    * SOURCE: Adapted from example code in "Pthreads Programming", B. Nichols
    *   et al. O'Reilly and Associates. 
    * LAST REVISED: 10/14/10  Blaise Barney
    ******************************************************************************/
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define NUM_THREADS  3
    #define TCOUNT 10
    #define COUNT_LIMIT 12
    
    int     count = 0;
    pthread_mutex_t count_mutex;
    pthread_cond_t count_threshold_cv;
    
    void *inc_count(void *t) 
    {
      int i;
      long my_id = (long)t;
    
      for (i=0; i < TCOUNT; i++) {
        pthread_mutex_lock(&count_mutex);
        count++;
    
        /* 
        Check the value of count and signal waiting thread when condition is
        reached.  Note that this occurs while mutex is locked. 
        */
        if (count == COUNT_LIMIT) {
          printf("inc_count(): thread %ld, count = %d  Threshold reached. ",
                 my_id, count);
          pthread_cond_signal(&count_threshold_cv);
          printf("Just sent signal.\n");
          }
        printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", 
           my_id, count);
        pthread_mutex_unlock(&count_mutex);
    
        /* Do some work so threads can alternate on mutex lock */
        /*sleep(1);*/
        }
      pthread_exit(NULL);
    }
    
    void *watch_count(void *t) 
    {
      long my_id = (long)t;
    
      printf("Starting watch_count(): thread %ld\n", my_id);
    
      /*
      Lock mutex and wait for signal.  Note that the pthread_cond_wait routine
      will automatically and atomically unlock mutex while it waits. 
      Also, note that if COUNT_LIMIT is reached before this routine is run by
      the waiting thread, the loop will be skipped to prevent pthread_cond_wait
      from never returning.
      */
      pthread_mutex_lock(&count_mutex);
      while (count < COUNT_LIMIT) {
        printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id,count);
        pthread_cond_wait(&count_threshold_cv, &count_mutex);
        printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id,count);
        printf("watch_count(): thread %ld Updating the value of count...\n", my_id,count);
        count += 125;
        printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
        }
      printf("watch_count(): thread %ld Unlocking mutex.\n", my_id);
      pthread_mutex_unlock(&count_mutex);
      pthread_exit(NULL);
    }
    
    int main(int argc, char *argv[])
    {
      int i, rc; 
      long t1=1, t2=2, t3=3;
      pthread_t threads[3];
      pthread_attr_t attr;
    
      /* Initialize mutex and condition variable objects */
      pthread_mutex_init(&count_mutex, NULL);
      pthread_cond_init (&count_threshold_cv, NULL);
    
      /* For portability, explicitly create threads in a joinable state */
      pthread_attr_init(&attr);
      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
      pthread_create(&threads[0], &attr, watch_count, (void *)t1);
      pthread_create(&threads[1], &attr, inc_count, (void *)t2);
      pthread_create(&threads[2], &attr, inc_count, (void *)t3);
    
      /* Wait for all threads to complete */
      for (i = 0; i < NUM_THREADS; i++) {
       /* pthread_join(threads[i], NULL);*/
      }
      printf ("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n", 
              NUM_THREADS, count);
    
      /* Clean up and exit */
      pthread_attr_destroy(&attr);
      pthread_mutex_destroy(&count_mutex);
      pthread_cond_destroy(&count_threshold_cv);
      pthread_exit (NULL);
    
    }
    

在 Mac OS X 10.9(Apple LLVM 版本 5.1 (clang-503.0.40))上,这将输出:

            Starting watch_count(): thread 1
            Main(): Waited and joined with 3 threads. Final value of count = 0. Done.
            inc_count(): thread 2, count = 1, unlocking mutex
            inc_count(): thread 3, count = 2, unlocking mutex
            watch_count(): thread 1 Count= 2. Going into wait...
            watch_count(): thread 1 Condition signal received. Count= 2
            watch_count(): thread 1 Updating the value of count...
            watch_count(): thread 1 count now = 127.
            watch_count(): thread 1 Unlocking mutex.
            inc_count(): thread 2, count = 128, unlocking mutex
            inc_count(): thread 3, count = 129, unlocking mutex
            inc_count(): thread 2, count = 130, unlocking mutex
            inc_count(): thread 3, count = 131, unlocking mutex
            inc_count(): thread 2, count = 132, unlocking mutex
            inc_count(): thread 3, count = 133, unlocking mutex
            inc_count(): thread 2, count = 134, unlocking mutex
            inc_count(): thread 3, count = 135, unlocking mutex
            inc_count(): thread 2, count = 136, unlocking mutex
            inc_count(): thread 3, count = 137, unlocking mutex
            inc_count(): thread 2, count = 138, unlocking mutex
            inc_count(): thread 3, count = 139, unlocking mutex
            inc_count(): thread 2, count = 140, unlocking mutex
            inc_count(): thread 3, count = 141, unlocking mutex
            inc_count(): thread 2, count = 142, unlocking mutex
            inc_count(): thread 3, count = 143, unlocking mutex
            inc_count(): thread 2, count = 144, unlocking mutex
            inc_count(): thread 3, count = 145, unlocking mutex

而在 CentOS 5 和 6(gcc 4.1.2 和 gcc 4.4.3 x86_64-redhat-linux)上,输出出现的更随机,有时是:

            Main(): Waited and joined with 3 threads. Final value of count = 0. Done.
            Starting watch_count(): thread 1
            watch_count(): thread 1 Count= 0. Going into wait...
            inc_count(): thread 2, count = 1, unlocking mutex
            inc_count(): thread 2, count = 2, unlocking mutex
            inc_count(): thread 2, count = 3, unlocking mutex
            inc_count(): thread 2, count = 4, unlocking mutex
            inc_count(): thread 2, count = 6, unlocking mutex
            inc_count(): thread 2, count = 7, unlocking mutex
            inc_count(): thread 2, count = 8, unlocking mutex
            inc_count(): thread 2, count = 9, unlocking mutex
            inc_count(): thread 2, count = 10, unlocking mutex
            inc_count(): thread 2, count = 11, unlocking mutex
            inc_count(): thread 3, count = 5, unlocking mutex

它挂起,有时它会给出:

            Main(): Waited and joined with 3 threads. Final value of count = 0. Done.
            Starting watch_count(): thread 1
            watch_count(): thread 1 Count= 0. Going into wait...
            inc_count(): thread 2, count = 1, unlocking mutex
            inc_count(): thread 2, count = 2, unlocking mutex
            inc_count(): thread 2, count = 3, unlocking mutex
            inc_count(): thread 2, count = 4, unlocking mutex
            inc_count(): thread 2, count = 5, unlocking mutex
            inc_count(): thread 2, count = 6, unlocking mutex
            inc_count(): thread 2, count = 7, unlocking mutex
            inc_count(): thread 2, count = 8, unlocking mutex
            inc_count(): thread 2, count = 9, unlocking mutex
            inc_count(): thread 3, count = 10, unlocking mutex
            inc_count(): thread 3, count = 11, unlocking mutex
            inc_count(): thread 3, count = 12  Threshold reached. inc_count(): thread 2, count = 13, unlocking mutex

并且还挂起。

总结一下:在 Mac OS X 上,如果我不睡觉inc_count并加入 main 中的 3 个线程,watch_count当 count 为 2 时,它将接收信号(显然不是由 2 个 inc_count 线程发出的信号),并且pthread_cond_signal永远不会被调用。

然而,在 Linux 上,它会在某个时候挂起。

我的问题是:如何pthread_join影响条件变量的行为?为什么 Mac OS X 的行为与 Linux 如此不同?

4

1 回答 1

0

取出pthread_join()可能是一个错误。启动了各种线程后,pthread_join()允许这些线程在退出之前完成。如果你不这样做,那么当程序退出时,所有未完成的线程都会被毫不客气地终止。您观察到的情况将取决于在斧头落下之前线程有多远。

sleep()只是减慢了速度,因此机制更加明显。

我怀疑这里的问题是pthread_cond_signal()如果没有服务员就没有效果......信号不记得了。条件应与其他状态一起使用。当状态更新时,相关条件用于表示状态已更改,以防某个线程正在等待。因此,涉及简单标志条件的等待将是:

pthread_mutex_lock(mutex) ;
while (!whatever)
  pthread_mutex_wait(condition, mutex) ;
pthread_mutex_unlock(mutex) ;

注意while--pthread_cond_signal()允许唤醒多个线程,所以从等待者的角度来看,被唤醒并不能保证状态已经改变,或者是等待的状态。

发出信号(我们假设在whatever其他地方初始化为假):

pthread_mutex_lock(mutex) ;
whatever = true ;
pthread_mutex_signal(condition) ;
pthread_mutex_unlock(mutex) ;

再次注意,该whatever标志是必不可少的,因为如果没有它,如果在服务员线程进入等待之前执行信号,服务员将永远等待!

说了这么多,我建议watch_count()功能坏了。

于 2014-07-21T20:27:13.210 回答