linux c++. Возврат к прерванному контексту после обработки сигнала

162
24 февраля 2018, 22:12

Есть метод вида:

ResultType Getter::get()
{
  std::unique_lock<std::mutex> lock(mx);
  Reader::readData();
}

Есть обработчик сигнала:

std::list<CommandMethod<>> Events;
std::mutex              lock;
std::condition_variable check;
bool notified=false;
void EventDispatcherThread()
{
    while (1)
    {
        std::unique_lock<std::mutex> locker(lock);
        while (!notified)
            check.wait(locker);
        while (Events.size() > 0)
        {
            Events.front()();
            Events.pop_front();
        }
        notified = false;
    }
}
CommandMethod<> event(&controller,&Controller::EventHandler, SIGSYS);
int main(int argc, char *argv[]) 
{
    std::thread sed_thread(&EventDispatcherThread);
    sed_thread.detach();
    std::signal(SIGSYS, [](int sig)->void {
        std::unique_lock < std::mutex> lock(g_lock);
        Events.push_back(event);
        notified = true;
        g_check.notify_all();
    });
    controller.main(argc, argv);
}

метод класса, который дергает обработчик:

Controller::EventHandler(int sig)
{
   /*......*/
   Getter::get();
}

метод класса, который исполняется в главном потоке.

Controller::main(int argc, char *argv[]) 
{
   /*......*/
   Getter::get();
}

Проблема в том, что сигнал срабатывющий, пока залочен мютекс в Getter::get() главного потока в методе Controller::main(int argc, char *argv[]) прерывает его выполнение, и после обработки сигнала переходит к выполнению void EventDispatcherThread(), который в свою очередь через Controller::EventHandler(int sig) тоже вызывает Getter::get(), тем самым возникает взаимоблокировка. Я понимаю, что обработчик сигнала может прервать контекст в любой момент, но как заставить его вернуться к прерванному контексту(в метод Controller::main(int argc, char *argv[])) после обработки сигнала, а не после обработки EventDispatcherThread()

Answer 1

Спасибо avp, за правильную ссылку. g_check.notify_all(); не является безопасной для обработчика сигналов. Поток Controller::EventHandler(int sig) пробуждался перед завершением обработчика сигнала, и ,видимо, по этой причине получал приоритет над основным потоком. Реализовал следующим образом:

sem_t sem;
void EventDispatcherThread()
{
    while (1)
    {
        sem_wait(&sem);
        controller.EventHandler(SIGSYS);
    }
}
int main(int argc, char *argv[]) 
{
    sem_init(&sem, 0, 10);
    for (int i = 0; i < 10; ++i)
        sem_wait(&sem);
    std::thread sed_thread(&EventDispatcherThread);
    sed_thread.detach();
    std::signal(SIGSYS, [](int sig)->void {
         sem_post(&sem);
    });
    controller.main(argc, argv);
}

Все оказалось намного проще.

Вопрос такого же плана: https://stackoverflow.com/questions/31117959/waking-up-thread-from-signal-handler

READ ALSO
Qt QCameraViewfinder

Qt QCameraViewfinder

Возможно ли как-то добавить классу QCameraViewfinder через сигнал или слот on_click как у обычной кнопки?

154
Есть виджеты реализованные для QT?

Есть виджеты реализованные для QT?

Мне нужен виджет секундомера, градусника, компаса и шкалы топливаВ одном стиле

156
Как исправить предупреждение: &#39;ksp_ecology::_Mkrt&#39; will be initialized after [-Wreorder] double _Mkrt;?

Как исправить предупреждение: 'ksp_ecology::_Mkrt' will be initialized after [-Wreorder] double _Mkrt;?

предупреждение: 'ksp_ecology::_Mkrt' will be initialized after [-Wreorder] double _Mkrt;

176
Совмещение CreateDirectory и fstream

Совмещение CreateDirectory и fstream

Я знаю, что папки создаются через CreateDirectory и что через fstream можно создать например текстовик с заданным текстом, а как их совместить? То есть...

199