Почему сигнал вместо широковещания работает, если нам нужно распечатать результаты многопоточных вычислений в определенном порядке? - PullRequest
0 голосов
/ 05 мая 2018

В моем коде ниже я создаю пул потоков, которые выполняют вычисления на общем массиве. Я хочу, чтобы вычисления выполнялись параллельно, однако, я хочу напечатать результаты вычислений так, чтобы идентификатор потока x не печатал свои результаты перед идентификатором потока y, где x> y. Итак, сначала я хочу напечатать результаты с идентификатором 0, затем 1, 2 и т. Д.

Я использую pthreads для этого. Первоначально я использовал pthread_cond_broadcast для пробуждения заблокированных потоков (все работало), но затем я попытался pthread_cond_signal просто из любопытства. Интересно, что программа по-прежнему работает правильно.

Но я не понимаю почему. То есть:

  1. Я порождаю, скажем, 5 потоков. Все они завершают свои расчеты.
  2. 4 из них блокируются, а идентификатор потока 0 печатает свой результат и сигнализирует.
  3. Согласно спецификации pthread_cond_signal "должен разблокировать хотя бы один из заблокированных потоков". Так что, возможно, он разблокирует идентификатор потока 3.
  4. Идентификатор потока 3 не может продолжаться, потому что еще не пришла его очередь печатать результат, поэтому он ждет.
  5. наступает тупик.

Так почему же pthread_cond_signal все еще работает? Это из-за неоднократного везения или из-за того, что моя ОС создает очередь заблокированных потоков, а идентификатор потока 1 просто находится в начале этой очереди?

Это мой код (логика ожидания / сигнала в функции ComputeThread):

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

#define DEFAULT_VAL 5
#define ARR_LEN 5
#define THREADS_NUM 5

typedef struct helper_t {
    int * currId;
    int threadId;
    int * computeArr;
    pthread_mutex_t * mutex;
    pthread_cond_t * cond;
} helper_t;

int * initComputeArr(int len) {
    int i;
    int * computeArr = (int *) malloc(sizeof(int) * len);
    for(i = 0; i < len; i++) {
        computeArr[i] = DEFAULT_VAL;
    }
    return computeArr;
}

void mallocError() {
    printf("malloc error\n");
    exit(EXIT_FAILURE);
}

helper_t * initHelpers(pthread_mutex_t * mutex, pthread_cond_t * cond, int * computeArr) {
    int i;
    helper_t * helpers = (helper_t *) malloc(sizeof(helper_t) * THREADS_NUM);
    int * currId = (int *) malloc(sizeof(int));
    if(!helpers || !currId) {
        mallocError();
    } else {
        *currId = 0;
        for(i = 0; i < THREADS_NUM; i++) {
            helpers[i].mutex = mutex;
            helpers[i].cond = cond;
            helpers[i].computeArr = computeArr;
            helpers[i].currId = currId;
            helpers[i].threadId = i;
        }
    }
    return helpers;
}

void printHelper(helper_t * h) {
    printf("threadId %d, currId %d\n", h->threadId, *h->currId);
}

void printHelpers(helper_t * h, int len) {
    int i;
    for(i = 0; i < len; i++) {
        printHelper(&h[i]);
    }
}

int calc(int * arr, int uptoIndex) {
    int i, sum = 0;
    for(i = 0; i <= uptoIndex; i++) {
        sum += arr[i];
    }
    return sum;
}

void * ComputeThread(void * arg) {
    int calcResult;
    helper_t * h = (helper_t *) arg;
    pthread_mutex_t * mutex = h->mutex;
    pthread_cond_t * cond = h->cond;
    calcResult = calc(h->computeArr, h->threadId);
    sleep(1);
    pthread_mutex_lock(mutex);
    while(*h->currId != h->threadId) {
        printf("id %d waiting...\n", h->threadId);
        pthread_cond_wait(cond, mutex);
    }
    printf("curr %d, threadId %d, result %d\n", *h->currId, h->threadId, calcResult);
    (*h->currId)++;
    pthread_cond_signal(cond);
    pthread_mutex_unlock(mutex);
    pthread_exit((void *) calcResult);
}

int main() {
    int i;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int * computeArr;
    int * calcResutls;
    helper_t * helpers;
    pthread_t threads[THREADS_NUM];

    computeArr = initComputeArr(ARR_LEN);
    calcResutls = initComputeArr(ARR_LEN);
    helpers = initHelpers(&mutex, &cond, computeArr);
    printHelpers(helpers, THREADS_NUM);

    for(i = 0; i < THREADS_NUM; i++) {
        pthread_create(&threads[i], NULL, ComputeThread, (void *) &helpers[i]);
    }

    for(i = 0; i < THREADS_NUM; i++) {
        pthread_join(threads[i], (void **) &calcResutls[i]);
    }

    for(i = 0; i < ARR_LEN; i++) {
        printf("%d, ", calcResutls[i]);
    }
    printf("\n");
    printf("end of calc\n");

    return 0;
}

1 Ответ

0 голосов
/ 05 мая 2018

Я вижу, как вызывается неопределенное поведение, поскольку код пропускает инициализацию мьютекса и условия.

...