Pthread выполнить неожиданно в C - PullRequest
0 голосов
/ 28 февраля 2020

Я хочу, чтобы pthreads мог выполнять свою задачу в указанном порядке:

поток 1 -> поток 3 -> поток 2

Когда я запускаю свой код, я обнаружил, что результат не зафиксировано. Моя ОС - 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;
}

Что за ошибка делает результат не исправленным?

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 28 февраля 2020

Вы неправильно используете переменные условия. Как указывает справочная страница Linux для pthread_cond_wait():

При использовании условных переменных всегда существует логический предикат, включающий общие переменные, связанные с каждым условным ожиданием, которое является истинным если поток должен продолжить. Могут возникнуть ложные пробуждения от функций pthread_cond_timedwait() или pthread_cond_wait(). Поскольку возврат из pthread_cond_timedwait() или pthread_cond_wait() не подразумевает ничего о значении этого предиката, предикат должен быть повторно оценен после такого возврата.

Это означает, что он не подходит для поток для интерпретации возврата из pthread_cond_wait() как признака того, что он должен продолжаться. Вместо этого он должен интерпретировать такой возврат как признак того, что он должен проверить некоторое условие, включающее одну или несколько общих переменных, чтобы определить, следует ли продолжить. Если условие не выполняется, то обычно следует подождать еще немного. Также обычно уместно проверить условие перед первым ожиданием, чтобы не пропустить сигнал.

Конечно, все обращения к общей переменной должны выполняться под защитой одного и того же мьютекса, по крайней мере, если любая из них может быть записана.

На принимающей стороне все выглядит примерно так:

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() может происходить и в защищенной мьютексом области - вам не нужно сначала разблокировать мьютекс - но, хотя ожидающий поток сразу же активируется (если он есть), он не будет продолжаться пока он не сможет вернуть мьютекс.

1 голос
/ 28 февраля 2020

Использование pthread_cond_wait вне условия (обычно al oop) для проверки некоторого условия, зависящего от состояния, защищенного мьютексом, всегда ошибка . В комментариях Драгошт отметил:

Вы не ожидаете, пока thread1 ожидает переменную условия

Но нет способа "ждать в потоке, чтобы ждать" на условной переменной ". Вместо этого поток не должен ожидать переменную условия, если условие, которое он ожидает, уже выполнено.

Вместо этого вы должны делать что-то вроде:

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

и поток сигнализации должен установить next_to_run до подачи сигнала (с удержанным мьютексом).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...