Pthread 在 C 中意外执行

Pthread execute unexpectedly in C

我想让 pthreads 可以运行它们的任务按指定的顺序:

线程 1 -> 线程 3 -> 线程 2

当我运行我的代码时,我发现结果不固定。 我的 OS 是 Ubuntu 16.04

有时结果是(意料之外的):

Before creating the threads
In thread1
In thread2
!!!!!!!!!!!!!!!!!!
I am thread1  generating the final report and inserting into a table 
In thread3

有时结果是(预期的):

Before creating the threads
In thread1
In thread2
In thread3
!!!!!!!!!!!!!!!!!!
I am thread1  generating the final report and inserting into a table
I am thread3  generating the final report and inserting into a table
I am thread2  generating the final report and inserting into a table
I am thread1  generating the final report and inserting into a table
I am thread3  generating the final report and inserting into a table
I am thread2  generating the final report and inserting into a table
I am thread1  generating the final report and inserting into a table
I am thread3  generating the final report and inserting into a table
I am thread2  generating the final report and inserting into a table
I am thread1  generating the final report and inserting into a table
I am thread3  generating the final report and inserting into a table

下面是我的代码:

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <signal.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;

int TRUE = 1;


void * threadMethod1(void *arg)
{
  printf("In thread1\n");
  do{
    pthread_mutex_lock(&lock1);
    //Add your business logic(parallel execution codes)  here
    pthread_cond_wait(&cond1, &lock1);
    printf("I am thread1  generating the final report and inserting into a table \n");
    pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
    pthread_mutex_unlock(&lock1);
  }while(TRUE);
  pthread_exit(NULL);
}

void * threadMethod2(void *arg)
{
  printf("In thread2\n");
  do
  {
    pthread_mutex_lock(&lock2);
    //Add your business logic(parallel execution codes)  here
    pthread_cond_wait(&cond2, &lock2);
    printf("I am thread2  generating the final report and inserting into a table \n");
    pthread_cond_signal(&cond1);
    pthread_mutex_unlock(&lock2);
  }while(TRUE);
  pthread_exit(NULL);
}

void * threadMethod3(void *arg)
{
  printf("In thread3\n");
  do
  {
    pthread_mutex_lock(&lock3);
    //Add your business logic(parallel execution codes)  here
    pthread_cond_wait(&cond3, &lock3);
    printf("I am thread3  generating the final report and inserting into a table \n");
    pthread_cond_signal(&cond2);
    pthread_mutex_unlock(&lock3);
  }while(TRUE);
  pthread_exit(NULL);
}


void my_alarm_handler(int a)
{
 TRUE = 0;//重新設定
}

int main(void)
{
  pthread_t tid1, tid2, tid3;
  int i = 0;

  signal( SIGALRM, my_alarm_handler );

  printf("Before creating the threads\n");
  if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
        printf("Failed to create thread1\n");
  if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
        printf("Failed to create thread2\n");
  if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
        printf("Failed to create thread3\n");
  pthread_cond_signal(&cond1);/* Now allow first thread to process first */

  alarm(1);
  //TRUE = 0;/* Stop all the thread */


 /* this is how we join thread before exit from a system */
  printf("!!!!!!!!!!!!!!!!!!\n");
  pthread_join(tid1,NULL);
  pthread_join(tid2,NULL);
  pthread_join(tid3,NULL);

  return 0;
}

什么错误导致结果不固定?

提前致谢!

在条件(通常是循环)之外使用 pthread_cond_wait 测试依赖于互斥锁保护的状态的某些条件总是错误。在评论中,dragosht 指出:

You're not waiting for thread1 to wait on the condition variable

但是没办法"wait on a thread to wait on the condition variable"。相反,如果线程等待的条件已经满足,则线程不得等待条件变量。

相反,您应该这样做:

while (next_to_run != MY_NUMBER)
    pthread_cond_wait(&cond, &lock);

并且信号线程应该在发出信号之前设置 next_to_run(保持互斥量)。

您错误地使用了条件变量。正如 the Linux manual page for pthread_cond_wait() 所说:

When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.

这意味着线程将 pthread_cond_wait() 中的 returning 解释为它应该继续的指示是不合适的。相反,它应该将这样的 return 解释为它应该 检查 一些涉及一个或多个共享变量的条件以确定它是否应该继续的标志。如果条件不满足,那么通常情况下,它应该再等一段时间。在第一次等待之前检查条件通常也是合适的,以避免错过信号。

当然,对共享变量的所有访问都应该在同一个互斥体的保护下执行,至少在其中任何一个可能是写入的情况下。

在接收方,一切看起来像这样:

pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
_Bool should_proceed1 = 0;

void *thread1(void *arg) {
    pthread_mutex_lock(&lock1);
    while (!should_proceed1) {
        pthread_cond_wait(&cond1, &lock1);
    }
    pthread_mutex_unlock(&lock1);

    // ...
}

在信令方面,它可能看起来像这样:

    pthread_mutex_lock(&lock1);
    should_proceed1 = 1;
    pthread_mutex_unlock(&lock1);
    pthread_cond_signal(&cond1);

注意,共享变量should_proceed1在两个地方都在同一个互斥锁的保护下被访问,这也是等待线程与CV相关联的互斥锁以进行等待。此外,pthread_cond_signal() 调用也可以发生在互斥锁保护区内——您不必先解锁互斥锁——但是尽管等待线程会立即唤醒(如果有的话),它会在它可以重新获取互斥锁之前不要继续。