pthread_join() для асинхронных потоков

Я написал простую демонстрационную программу, чтобы понять функцию pthread_join().

Я знаю, как использовать функцию pthread_condition_wait(), чтобы разрешить асинхронную поточность, но я пытаюсь понять, как я могу выполнять аналогичную работу, используя функцию pthread_join().

В приведенной ниже программе я передаю идентификатор Thread 1s в функцию Thread 2s. Внутри функции Thread 2s я вызываю функцию pthread_join() и передаю идентификатор Thread 1s. Я ожидал, что это приведет к тому, что Thread 1 запустится первым, а затем Thread 2 запустится вторым, но я получаю, что они оба запускаются одновременно.

Это потому, что только один поток может одновременно использовать функцию pthread_join(), а я уже использую функцию pthread_join(), когда вызываю ее из основного потока?

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

void *functionCount1();
void *functionCount2(void*);

int main()
{

    /* 
        How to Compile
         gcc -c foo
         gcc -pthread -o foo foo.o
    */

    printf("\n\n");

    int rc;
    pthread_t thread1, thread2;

    /* Create two thread --I took out error checking for clarity*/
    pthread_create( &thread1, NULL, &functionCount1, NULL)
    pthread_create( &thread2, NULL, &functionCount2, &thread1)

    pthread_join( thread1, NULL);
    pthread_join( thread2, NULL);

    printf("\n\n");
    exit(0);
}

void *functionCount1()
{

    printf("\nFunction 1");
        sleep(5);
    printf("\nFunction 1");

    return(NULL);
}

void *functionCount2(void* argument)
{

    pthread_t* threadID = (pthread_t*) argument;

    pthread_join(*threadID, NULL);

    printf("\nFunction 2");
        sleep(5);
    printf("\nFunction 2");

    return(NULL);
}

Выход:

введите здесь описание изображения


person Kyle Bridenstine    schedule 12.11.2014    source источник


Ответы (3)


Когда потоки создаются с использованием pthread_create(), оба потока начинают выполнение одновременно, и нет фиксированного порядка их выполнения. Порядок зависит от планирования ОС, количества доступных процессоров и т. д. В любом случае, это невозможно определить, и в любом случае это точка потоков.

Что происходит, когда вы вызываете pthread_join(), вызывающий объект ожидает завершения потока, который объединяется с. Таким образом, основной поток ожидает завершения thread1, а затем thread2. Но пока main ожидает thread1, thread2 может уже закончить выполнение и завершиться. В этом случае pthread_join(thread2, NULL); вернется немедленно.

У вас есть большая проблема в вашем коде. Вы передаете идентификатор thread1 thread2. Но если thread1 завершит выполнение до того, как начнется thread2, то вы будете использовать неверный идентификатор потока, что приведет к неопределенному поведению. Другая проблема заключается в том, что ваш основной поток и thread2 пытаются присоединиться к thread1. Короче говоря, pthread_join() не подходит для синхронизации между несколькими потоками. Как вы сказали, для этой цели вы используете условную переменную/мьютексы.

Я предлагаю вам удалить pthread_join() из thread2, чтобы исправить неопределенное поведение, и если вы хотите последовательное выполнение потоков, то вам нужно создавать потоки один за другим, позволять им и ждать завершения предыдущего потока (pthread_join()). Но практической пользы от этого очень мало. Или позвольте потокам ожидать условную переменную, прежде чем что-либо делать, и вы можете заставить потоки общаться в желаемом порядке, используя условные переменные.

person P.P    schedule 12.11.2014
comment
Я думаю, что основной причиной проблемы является вызов pthread_join( thread1, NULL); из main(): это приводит к возможности одновременного присоединения, которая не определена. Удаление также должно исправить проблему с недопустимым идентификатором потока, потому что поток 1 останется не присоединенным до вызова из потока 2. - person Sergey Kalinichenko; 12.11.2014
comment
@dasblinkenlight Это очень верное замечание. Я тоже обновлю это. Спасибо! - person P.P; 12.11.2014

Вы вызываете неопределенное поведение. справочная страница: http://man7.org/linux/man-pages/man3/pthread_join.3.html

Joining with a thread that has previously been joined results in undefined behavior.

Также первый поток может завершить выполнение раньше второго потока. Если вы хотите что-то подобное, лучше использовать pthread_cond_wait().

person rowan.G    schedule 12.11.2014

Из справочной страницы pthread_join (выделено мной):

Если несколько потоков одновременно попытаются присоединиться к одному и тому же потоку, результаты будут неопределенными. Если поток, вызывающий pthread_join(), будет отменен, то целевой поток останется доступным для присоединения (т. е. он не будет отсоединен). .

Кажется, что вы находитесь именно в этой ситуации, когда основной поток и поток 2 пытаются pthread_join поток 1.

Вы должны четко определить для каждого потока один «поток-владелец», который отвечает за его управление. Цепочка ответственности должна формировать иерархическое дерево потоков (т. е. без циклов или нескольких родителей).

person didierc    schedule 12.11.2014