2016-08-01 7 views
0

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

т.е..,

массив = {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 в функции calculate_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; 
} 
+0

«Почему нет никаких вкладок перед« Новой суммой »для первых 3 строк?» - есть. – immibis

ответ

4

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

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

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

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

+0

О, верно! Это была моя первоначальная реализация, но мне не нравилась мысль о malloc и освобождении каждый раз, поэтому я пошел с этим! Хорошо, что имеет смысл, я пойду попробовать! – vgbcell

+0

@vgbcell Вы также можете использовать локальный массив и передать каждому потоку указатель на другой элемент массива (и убедитесь, что массив не будет уничтожен до тех пор, пока все потоки не будут выполнены с их частями массива) – immibis