2013-12-24 2 views
0

Я пытаюсь сделать простую программу с помощью pthreads, хочу сделать 6 потоков и передать индекс всем из них. вот код:Программа pthreads не очень хорошо работает

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

#define num_students 6 

void thread_starter(); 

int main() { 
    pthread_t thread1[num_students]; 

    int i = 0; 
    for(i = 0; i<num_students; i++) { 
     int q = i; 
     pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q); 
     } 
    sleep(1); 
} 


void thread_starter(void* a) { 
    printf("Thread %i \n", *((int*)a)); 
} 

И выход:

Thread 2 
Thread 3 
Thread 2 
Thread 4 
Thread 5 
Thread 5 

почему они commmon имена? что не так?

Благодаря

ответ

2

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

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

Самый простой способ сделать это в вашем примере использовать другую автоматическую переменную для хранения данных, передаваемых в новых нитей

void thread_starter(void* a); 
int main() { 
    pthread_t thread1[num_students]; 
    int thread_data[num_students]; 
    int i = 0; 
    for(i = 0; i<num_students; i++) { 
     thread_data[i] = i; 
     pthread_create(&thread1[i], NULL, thread_starter, &thread_data[i]); 
    } 
    sleep(1); 
} 

Заметим также, что вы можете избежать того, чтобы бросить thread_starter если вы даете его правильная подпись в вашей декларации.

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

int main() { 
    pthread_t thread1[num_students]; 
    int i = 0; 
    for(i = 0; i<num_students; i++) { 
     int* data = malloc(sizeof(*data)); 
     *data = i; 
     pthread_create(&thread1[i], NULL, thread_starter, data); 
    } 
    sleep(1); 
} 

void thread_starter(void* a) { 
    printf("Thread %i \n", *((int*)a)); 
    free(a); 
} 

Наконец, используя sleep(1) не очень строгий способ гарантировать, что все ваши потоки будут работать. Было бы лучше использовать pthread_join вместо

for(i = 0; i<num_students; i++) { 
    pthread_join(thread1[i], NULL); 
} 
+0

aaah спасибо, да, имеет смысл, спасибо :)) –

1

sleep не является правильным инструментом ждать порождены потоков, используйте pthread_join для этого.

Ваш main завершение функции эквивалентно вызову exit для всей программы и уничтожению всех остальных тем.

1

Попробуйте это для вариации

void thread_starter(void* a) { 
// Put a sleep(1) Here and see you will get even bizarre results 
printf("Thread %i \n", *((int*)a)); 
} 

Ok проблема здесь, конечно

условие гонки в этот момент здесь

int q = i; 
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q); 

позволяет сказать, что создается первый поток и значение при q равно 0

Предположим теперь, что перед выполнением инструкции Здесь

printf("Thread %i \n", *((int*)a)); 

, если основной поток петли дальше и выполняет это утверждение здесь

int q = i; 

снова, то изменения д значение (поскольку его ссылки), следовательно, проблема

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

Жаль, что я был на Спеши еще несколько советов с моей стороны

#define num_students 6 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // A Global Mutex 

Будет aquire замок Здесь

pthread_mutex_lock(&mutex); 
    printf("\n Got Mutex %d\n", i); 
    int q = i; 
    pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q); 

и освободить замок Здесь в ребенке Рутинного

int i = *((int*)a); 
sleep(1); 
pthread_mutex_unlock(&mutex); 
printf("Thread %i \n", i); 

PS - удалить ненужные копии и спальные места, если они когда-либо не применимы

+0

Как копирование 'a' внутри' thread_starter' помогает? Его значение, возможно, уже было изменено. Если вы рекомендуете использовать мьютекс, ваш ответ может сделать некоторые разъяснения. – simonc

Смежные вопросы