Поток C ++, эквивалентный pthread_exit - PullRequest
0 голосов
/ 18 апреля 2020

Мне нужен C ++ эквивалент pthread_exit, чтобы сделать функцию, которая при вызове вызывает вызывающий поток для выхода.

В C, используя pthreads.h, я просто вызвал pthread_exit. Я новичок в C ++ и мне нужно использовать <thread>, для которого я не могу найти подобную функцию.

Я использую C ++ 17, и код должен компилироваться на Linux (и возможно на MacO).

Ответы [ 2 ]

3 голосов
/ 18 апреля 2020

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

Например:

#include <iostream>
#include <thread>
#include <exception>

class thread_exit_exception : public std::exception {};

void thread_subfunc ()
{
    std::cout << "Entering thread_subfunc\n";
    thread_exit_exception e;
    throw e;
    std::cout << "Leaving thread_subfunc (never executed)\n";
}

void thread_func ()
{
    std::cout << "Entering thread_func\n";
    try
    {
        thread_subfunc ();
    }
    catch (const thread_exit_exception&)
    {
    }
    std::cout << "Leaving thread_func\n";
}

int main()
{
    std::cout << "Entering main\n";
    std::thread t = std::thread (thread_func);
    t.join ();
    std::cout << "Leaving main\n";
}

Вывод:

Entering main
Entering thread_func
Entering thread_subfunc
Leaving thread_func
Leaving main

Живая демоверсия

1 голос
/ 18 апреля 2020

C ++ более зависим от своего стека вызовов, чем C. Программы на C ++ часто используют RAII, что означает, что ресурсы связаны с объектами, которые часто живут в стеке. Пользователи таких объектов ожидают, что эти объекты будут уничтожены должным образом. Если функция создает объект стека, она ожидает, что в какой-то момент в будущем управление вернется к этой функции, и объект стека будет уничтожен.

Таким образом, для потока с некоторым механизмом не существует глубина стека до go. std::thread заканчивается только тогда, когда достигнут конец функции, переданной конструктору thread (исключение, вызванное функцией потока, вызывает std::terminate).

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

Например, типичный способ работы пула потоков состоит в том, что каждый поток Функция main переходит в режим ожидания, ожидая, когда какая-либо форма задачи будет удалена для этого потока. Когда задача доступна, она выполняет эту задачу. По завершении задачи она проверяет наличие новой задачи и, если ее нет, возвращается в спящий режим до тех пор, пока задача не будет готова.

В таком пуле потоков ни один поток никогда не останавливается . Отдельные задачи останавливаются, но фактическое std::thread является вечным (или, по крайней мере, живет так же долго, как и пул).

Если задача должна завершиться, то такое завершение, по сути, представляет собой неисполнение задачи. В C ++ это пишется как «выбрасывание исключения». Основной поток помещает все вызовы задач в блок try, с блоком catch для указанного типа исключения c. Затем он может сообщить кому-либо о сбое задачи, а затем go проверить наличие новой задачи.

И это гарантирует, что стек вызовов задачи очищен.

...