Передача параметра в pthread - PullRequest
4 голосов
/ 17 апреля 2010

У меня есть следующий код:

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

#define NUM_THREADS 100

struct thread_param {
    char *f1;
    char *f2;
    int x;
};

void *thread_function(void *arg){
    printf("%d\n", ((struct thread_param*)arg)->x);
}

int main(int argc, char *argvs[]){
    int i, thread_cr_res = 0, thread_join_res;
    pthread_t *threads;
    threads = malloc(100 * sizeof(*threads));
    if(threads == NULL){
        fprintf(stderr,"MALLOC THREADS ERROR");
        return (-1);
    }
    for(i = 0; i < NUM_THREADS; i++){
        struct thread_param *tp;
        if((tp = malloc(sizeof(*tp))) == NULL){
            fprintf(stderr,"MALLOC THREAD_PARAM ERROR");
            return (-1);
        }
        tp->f1 = "f1";
        tp->f2 = "f2";
        tp->x = i;
        thread_cr_res = pthread_create(&threads[i], 
                    NULL, 
                    thread_function, 
                    (void*)tp);
        if(thread_cr_res != 0){
            fprintf(stderr,"THREAD CREATE ERROR");
            return (-1);
        }
    }
    return (0);
}

Чего я хочу добиться, так это распечатать все числа от 0 до 99 из потоков. Также я экспериментирую способ передачи структуры в качестве входного параметра потока.

Что я нахожу в курьезах, так это то, что отображаются не все цифры, например:

 ./a.out | grep 9
9
19
29
39
49

А иногда некоторые цифры показываются дважды:

...
75
74
89
77
78
79
91
91

Не могли бы вы объяснить, почему это происходит? Ошибки не отображаются.

ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ: Я переписал код, как предложил @Yasir, используя pthread_join. Новый код выглядит так:

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

#define NUM_THREADS 100

struct thread_param {
    char *f1;
    char *f2;
    int x;
};

void *thread_function(void *arg){
    printf("%d\n", ((struct thread_param*)arg)->x);
}

int main(int argc, char *argvs[]){
    int i, thread_cr_res = 0, thread_join_res;
    pthread_t *threads;
    threads = malloc(100 * sizeof(*threads));
    if(threads == NULL){
        fprintf(stderr,"MALLOC THREADS ERROR");
        return (-1);
    }
    for(i = 0; i < NUM_THREADS; i++){
        struct thread_param *tp;
        if((tp = malloc(sizeof(*tp))) == NULL){
            fprintf(stderr,"MALLOC THREAD_PARAM ERROR");
            return (-1);
        }
        tp->f1 = "f1";
        tp->f2 = "f2";
        tp->x = i;
        thread_cr_res = pthread_create(&threads[i], 
                    NULL, 
                    thread_function, 
                    (void*)tp);
        if(thread_cr_res != 0){
            fprintf(stderr,"THREAD CREATE ERROR");
            return (-1);
        }
    }
    /* Later edit, joining the threads */
    for (i = 0; i < NUM_THREADS; i++){
        thread_join_res = pthread_join(threads[i], NULL);
        if(thread_join_res != 0){
            fprintf(stderr, "JOIN ERROR");
            return (-1);
        }       
    }
    return (0);
}

После того, как:

./a.out | sort
0
1
10
11
12
13
14
15
16
17
18
19
2
20
21
22
23
24
25
26
27
28
29
3
30
31
32
33
34
35
36
37
38
39
4
40
41
42
43
44
45
46
47
48
49
5
50
51
52
53
54
55
56
57
58
59
6
60
61
62
63
64
65
66
67
68
69
7
70
71
72
73
74
75
76
77
78
79
8
80
81
82
83
84
85
86
87
88
89
9
90
91
92
93
94
95
96
97
98
99

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

Ответы [ 2 ]

2 голосов
/ 17 апреля 2010

Используйте int pthread_join(pthread_t thread, void **value_ptr) для ожидания завершения потоков, чтобы получить все результаты до выхода из основного потока. Также из-за sizeof(*tp) вы получите размер указателя на эту структуру, который составляет 4 байта в 32-битной системе. Это может переписать другие структуры в памяти. sizeof(thread_param) будет иметь больше смысла для меня. Также tp->f1 = "f1"; относится к одной константной строке. И. е. Вы не сохраняете строку в структуре, а используете один и тот же буфер для всех ваших thread_param структур. Это было бы небезопасно, если "f1" - указатель на буфер переменной.

UPD: Да, комментарии ниже о размере верны.

1 голос
/ 22 февраля 2011

Код работает так, как должен. Тем не менее я не могу объяснить, почему первая версия кода выводила дубликаты.

Это, вероятно, связано с тем, как stdio работает между потоками: чтобы не повредить вывод (и вообще любой другой поток), stdio использует блокировку. И если ваш основной поток завершит работу, могут произойти плохие вещи, такие как закрытие потоков, которые должны быть открыты / сброшены другими потоками.

Обратите внимание, что, поскольку функция stdio заблокирована, существует конфликт и вызов printf () стал своего рода точкой синхронизации, которая изменит способ работы вашей программы.

...