Выполнить функцию обратного вызова в главном потоке из std:: thread


У меня есть требование выполнения функции обратного вызова при выходе из потока std::, и функция обратного вызова должна выполняться в основном потоке.

При создании потока мне нужно отсоединить поток и не могу заблокировать выполнение основного цикла для завершения потока.

Я пытался использовать std:: signal, но это не похоже на выполнение функции обратного вызова в главном потоке

#include <thread>
#include <csignal>
#include <iostream>


std::thread::id main_thread_id;

void func2()
{
    for(int i = 0; i < 10000000; i++)
    {
        // do something
    }
}

void func()
{
    for(int i = 0; i < 10; i++)
    {
        func2();
    }
    std::raise(SIGUSR1);
}

void callback(int signal)
{
    std::cout << "SIGNAL: " << signal << "      THREAD ID:" << 
    std::this_thread::get_id() << std::endl;
    bool b = std::this_thread::get_id() == main_thread_id;
    std::cout << "IS EXECUTED ON MAIN THREAD: " << b << std::endl;
}

int main()
{
    main_thread_id = std::this_thread::get_id();
    std::cout << "MAIN THREAD ID: " << std::this_thread::get_id() << std::endl;
    std::signal(SIGUSR1, callback);
    std::thread t1(func);
    t1.detach();

    for(int i = 0; i < 20; i++)
    {
        func2();
    }

    if(t1.joinable())
        t1.join();
}

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

Спасибо за помощь

1 2

1 ответ:

Есть несколько способов сделать это.

Во-первых, ваш основной поток может выполнять цикл сообщений . В этом случае вы ставите в очередь сообщение с полезной нагрузкой, которая говорит главному потоку выполнить некоторый код (либо переносите код для выполнения через часть указателя сообщения к главному потоку, либо помещаете его в известное место, которое проверяет главный поток). Второй подход состоит в том, чтобы вернуть что-то вроде объекта std::future<std::function<void()>>, и главный поток проверяет, готово ли будущее. Когда это так готово, он запускает код. Третий подход состоит в том, чтобы создать параллельную очередь, которую ожидает основной поток, и поместить ваше сообщение (содержащее код для запуска) в эту очередь. Все это требует активного сотрудничества с главной нитью. Основной поток не может быть вытеснен и приказан выполнять другой код без его сотрудничества.

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