C, pthreads, инициализированный в цикле, не выполняет назначенную функцию должным образом, несмотря на мьютекс

У меня возникают проблемы при отладке моей программы на C, цель которой состоит в том, чтобы создать 5 потоков, каждый из которых должен работать с кусками размера 2 массива длиной 10. Цель - получить сумму этого массива. Моя настоящая программа немного менее тривиальна, чем эта, поскольку она принимает динамические размеры массива и число потоков, но я попытался упростить ее до этой простой проблемы, и она все еще не работает.

то есть.,

массив = {1 2 3 4 5 6 7 8 9 10}

тогда thread1 работает с массивом [0] и массивом [1]

и thread2 работает с массивом [2] и массивом [3]

так далее...

thread5 работает с массивом [8] и массивом [9]

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

Например, это один из моих результатов при запуске этой программы.

Thread #1 adding 3 to 0 New sum: 3
Thread #1 adding 4 to 3 New sum: 7
Thread #2 adding 5 to 7 New sum: 12
Thread #2 adding 6 to 12        New sum: 18
Thread #3 adding 7 to 18        New sum: 25
Thread #3 adding 8 to 25        New sum: 33
Thread #4 adding 9 to 33        New sum: 42
Thread #4 adding 9 to 42        New sum: 51
Thread #4 adding 10 to 51       New sum: 61
Thread #4 adding 10 to 61       New sum: 71
Sum: 71

Прежде всего, почему до "новой суммы" нет первых вкладок для первых 3 строк? (см. мой журнал printf в функции calc_sum). И что еще более важно, почему thread0 никогда не выполняет свою работу и почему поток 4 выполняет дважды?

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

typedef struct {
    int start, end, thread_number;
    int *data;
} Func_args;

static pthread_mutex_t mutex;
static int sum = 0;

void *calculate_sum(void *args) {

    int *arr = ((Func_args *)args)->data;
    int i = ((Func_args *)args)->start;
    int end = ((Func_args *)args)->end;
    int t_id = ((Func_args *)args)->thread_number;

    while (i < end) {
        pthread_mutex_lock(&mutex);
        printf("Thread #%d adding %d to %d\t", t_id, arr[i], sum);
        sum += arr[i++];
        printf("New sum: %d\n", sum);
        pthread_mutex_unlock(&mutex);
    }

    return NULL;
}

#define NUM_THREAD 5
#define ARRAY_LEN 10

int main(int argc, char **argv) {

    int array[ARRAY_LEN] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    pthread_t tid[NUM_THREAD];
    int i, pos = 0;

    pthread_mutex_init(&mutex, NULL);

    for (i = 0; i < NUM_THREAD; i++) {
        Func_args args;
        args.data = array;
        args.thread_number = i;
        args.start = pos;
        pos += 2;
        args.end = pos;
        pthread_create(&tid[i], NULL, calculate_sum, &args);
    }

    for (i = 0; i < NUM_THREAD; i++)
        pthread_join(tid[i], NULL);

    pthread_mutex_destroy(&mutex);
    printf("Sum: %d\n", sum);

    return 0;
}

1 ответ

Вы передаете каждому потоку указатель на объект, который может быть уничтожен до запуска потока.

args является локальным, поэтому уничтожается, когда программа выходит из области, в которой она была объявлена, то есть в конце for тело петли.

Запуск потока может занять несколько секунд, поэтому, если поток запускается после этого, он получит доступ к уничтоженному объекту - на практике память будет использоваться повторно для хранения значений следующего потока.

Вы можете исправить это, динамически распределяя данные потока с помощью malloc (и не забывая free это в потоке или если pthread_create завершится неудачно).

Другие вопросы по тегам