Подтвердить что ты не робот

Return() в сравнении с pthread_exit() в функциях запуска pthread

Следующая программа показывает, что мы можем использовать return или pthread_exit для возврата переменной void* которая доступна для переменной состояния pthread_join.

  1. Должны ли быть предпочтения для использования одного над другим?

  2. Почему использование возврата работает? Обычно мы думаем о возвращении, помещающем значение в стек, но поскольку поток завершен, стек должен исчезнуть. Или стек не разрушается до окончания pthread_join?

  3. Видите ли вы в своей работе большую переменную состояния? Кажется, 90% кода, который я вижу, просто обнуляет параметр состояния. Поскольку все, что было изменено с помощью void* ptr, уже отражено в вызывающем потоке, нет особого смысла его возвращать. Любой новый возвращаемый void* ptr должен указывать на что-то, что было malloc определено начальным потоком, что оставляет принимающий поток с ответственностью за его удаление. Я ошибаюсь, думая, что переменная состояния является полубессмысленной?

Вот код:

#include <iostream>
#include <pthread.h>

using namespace std;

struct taskdata
{
       int  x;
     float  y;
    string  z;
};


void* task1(void *data)
{
    taskdata *t = (taskdata *) data;

    t->x += 25;
    t->y -= 4.5;
    t->z = "Goodbye";

    return(data);
}

void* task2(void *data)
{
    taskdata *t = (taskdata *) data;

    t->x -= 25;
    t->y += 4.5;
    t->z = "World";

    pthread_exit(data);
}


int main(int argc, char *argv[])
{
    pthread_t threadID;

    taskdata t = {10, 10.0, "Hello"};

    void *status;

    cout << "before " << t.x << " " << t.y << " " << t.z << endl;

    //by return()

    pthread_create(&threadID, NULL, task1, (void *) &t);

    pthread_join(threadID, &status);

    taskdata *ts = (taskdata *) status;

    cout << "after task1 " << ts->x << " " << ts->y << " " << ts->z << endl;

    //by pthread_exit()

    pthread_create(&threadID, NULL, task2, (void *) &t);

    pthread_join(threadID, &status);

    ts = (taskdata *) status;

    cout << "after task2 " << ts->x << " " << ts->y << " " << ts->z << endl;

}

С выводом:

before 10 10 Hello
after task1 35 5.5 Goodbye
after task2 10 10 World
4b9b3361

Ответ 1

(1) В коде С++ использование return приводит к размыванию стека, а локальные переменные уничтожаются, тогда как pthread_exit гарантируется только при вызове обработчиков отмены, зарегистрированных с помощью pthread_cancel_push(). В некоторых системах этот механизм также будет вызывать деструкторы для локальных переменных С++, но это не гарантируется для переносного кода --- проверьте документацию на платформе.

Кроме того, в main(), return будет неявно вызывать exit() и, таким образом, завершать программу, тогда как pthread_exit() просто прекратит поток, и программа будет продолжать работать до тех пор, пока все потоки не будут завершены или не будет какой-либо поток вызывает exit(), abort() или другую функцию, которая завершает работу программы.

(2) Использование return работает, потому что это говорит о спецификации POSIX. Возвращаемое значение сохраняется в месте, где pthread_join() может его получить. Ресурсы, используемые потоком, не возвращаются до тех пор, пока не вызывается pthread_join().

(3) Я никогда не использую возвращаемое значение потока в сырых потоках POSIX. Тем не менее, я имею тенденцию использовать объекты более высокого уровня, такие как библиотека потоков Boost, а в последнее время - библиотеку потоков С++ 0x, которые предоставляют альтернативные средства для передачи значений между потоками, такими как фьючерсы, которые позволяют избежать проблем, связанных с управлением памятью, что вы ссылаться на.

Ответ 2

Я думаю, что return из start_routine предпочтительнее, потому что он гарантирует, что стек вызовов будет правильно размотан.

Это еще более важно для C, чем С++, поскольку у него нет магии деструктора, которая очищает беспорядок после предварительных выходов. Таким образом, ваш код должен пройти через все заключительные части подпрограмм в стеке вызовов, чтобы сделать free и аналогично.

Для чего это работает, это просто

Если start_routine возвращается, эффект должен быть таким, как если бы существовал неявный вызов pthread_exit() с использованием возвращаемого значения start_routine как статус выхода

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