Почему printf не работает с несколькими потоками в c? - PullRequest
0 голосов
/ 02 мая 2018

В приведенном ниже коде я создаю 8 потоков, каждый из которых печатает строку и ее идентификатор. Однако я не вижу вывода printf в функции stdout из PrintHello. Одна странная вещь, которая происходит, заключается в том, что если запустить main с помощью отладчика (CLion) printf, то на самом деле выводит намеченный результат. Я на самом деле подозреваю, что не работает ни один код внутри PrintHello функции, а только printf. Что может быть причиной этого?

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

Это код (адаптированный к этим слайдам ):

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

#define BAD_EXIT 1
#define NUM_TASKS 8

char * messages[NUM_TASKS];

void * PrintHello(void * taskIdPtr) {
    int taskId;
    sleep(1);
    taskId = *((int *) taskIdPtr);
    printf("Task id = %d, message = %s\n", taskId, messages[taskId]);
    free(taskIdPtr);
    pthread_exit(NULL);
}
int main(int argc, char ** argv) {
    pthread_t threads[NUM_TASKS];
    int * taskIdPtr;
    int rc, t;
    messages[0] = "English: Hello World!";
    messages[1] = "French: Bonjour, le monde!";
    messages[2] = "Spanish: Hola al mundo";
    messages[3] = "Klingon: Nuq neH!";
    messages[4] = "German: Guten Tag, Welt!";
    messages[5] = "Russian: Zdravstvytye, mir!";
    messages[6] = "Japan: Sekai e konnichiwa!";
    messages[7] = "Latin: Orbis, te saluto!";

    for(t = 0; t < NUM_TASKS; t++) {
        taskIdPtr = (int *) malloc(sizeof(int));
        *taskIdPtr = t;
        printf("Creating thread %d\n", t);
        rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskIdPtr);
        if(rc) {
            perror("Error :");
            exit(BAD_EXIT);
        }
    }
    return 0;
}

Ответы [ 2 ]

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

Проблема в том, что ваш основной поток завершает свое выполнение и завершает работу, прежде чем любой другой дочерний поток даже напечатает одно сообщение (поскольку в вашем дочернем потоке вы ждете 1 секунду, прежде чем что-либо делать).

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

Ниже приводится выдержка из справочной страницы linux pthread_create():

Новый поток завершается одним из следующих способов :

  • Вызывает pthread_exit (3), указывая значение состояния выхода, доступное для другого потока в том же процессе, который вызывает pthread_join (3).
  • Возвращается из start_routine (). Это эквивалентно вызову pthread_exit (3) со значением, указанным в операторе возврата.
  • Отменено (см. Pthread_cancel (3)).
  • Любой из потоков в процессе вызывает exit (3), или основной поток выполняет возврат из main () . Это вызывает завершение всех потоков в процессе.

Для решения этой проблемы вы должны использовать int pthread_join(pthread_t thread, void **retval).

Ниже приведен исправленный код. Посмотрите здесь работает :

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

#define BAD_EXIT 1
#define NUM_TASKS 8

char * messages[NUM_TASKS];

void * PrintHello(void * taskIdPtr) {
    int taskId;
    sleep(1);
    taskId = *((int *) taskIdPtr);
    printf("Task id = %d, message = %s\n", taskId, messages[taskId]);
    free(taskIdPtr);
    pthread_exit(NULL);
}
int main(int argc, char ** argv) {
    pthread_t threads[NUM_TASKS];
    int * taskIdPtr;
    int rc, t;
    messages[0] = "English: Hello World!";
    messages[1] = "French: Bonjour, le monde!";
    messages[2] = "Spanish: Hola al mundo";
    messages[3] = "Klingon: Nuq neH!";
    messages[4] = "German: Guten Tag, Welt!";
    messages[5] = "Russian: Zdravstvytye, mir!";
    messages[6] = "Japan: Sekai e konnichiwa!";
    messages[7] = "Latin: Orbis, te saluto!";

    for(t = 0; t < NUM_TASKS; t++) {
        taskIdPtr = (int *) malloc(sizeof(int));
        *taskIdPtr = t;
        printf("Creating thread %d\n", t);
        rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskIdPtr);
        if(rc) {
            perror("Error :");
            exit(BAD_EXIT);
        }
    }

    for(t = 0; t < NUM_TASKS; t++)
    {
        pthread_join(threads[t], NULL);
    }
    return 0;
}
0 голосов
/ 02 мая 2018

Основной процесс завершается до запуска вновь созданных потоков. Поэтому вам следует дождаться потоков, созданных с использованием pthread_join.

Согласно справочной странице pthread_join

int pthread_join(pthread_t thread, void **retval);

Функция pthread_join () ожидает завершения потока, указанного потоком. Если этот поток уже завершен, то функция pthread_join () возвращается немедленно. Поток, указанный в thread, должен быть присоединяемым.

...