Есть метод вида:
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()
Спасибо 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
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости