【问题标题】:Guaranteed yielding with pthread_cond_wait and pthread_cond_signal使用 pthread_cond_wait 和 pthread_cond_signal 保证让步
【发布时间】:2010-11-16 09:50:19
【问题描述】:

假设我有一个具有 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 );
}

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

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

【问题讨论】:

    标签: c multithreading pthreads mutex condition-variable


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      这是我在standard 中找到的:

      4.13 调度策略

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

      [...]

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

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

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

      【讨论】:

        【解决方案3】:

        根据pthread_cond_wait 手册页

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

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

        【讨论】:

        • 严格来说,静态优先级高于写入线程的 SCHED_FIFO 或 SCHED_RR 在单处理器系统上可以工作。但在 SMP 上,您仍然可以争夺锁定。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-18
        相关资源
        最近更新 更多