@ Тимоти, это правильная ссылка, я отредактировал свой ответ. Я не слишком знаком со стандартом C, хотя у меня никогда не было проблем с использованием только функций, перечисленных в справочной странице по сигналам из обработчика сигналов.

у кроссплатформенную серверную программу на C ++, используя Boost.Asio. Следуя примеру HTTP-сервера наэта страница, Я хотел бы обработать запрос на завершение работы пользователя без использования API, специфичных для реализации. Первоначально я пытался использовать стандартную библиотеку сигналов С, но не смог найти шаблон проектирования, подходящий для Asio.Пример Windows Дизайн кажется похожим на библиотеку сигналов ближе всего, но есть условие гонки, когда обработчик консоли ctrl может быть вызван после уничтожения объекта сервера. Я пытаюсь избежать неопределенного поведения, как указано в стандарте C ++.

Есть ли стандартный (и правильный) способ остановить сервер?

Чтобы проиллюстрировать проблемы с использованием библиотеки сигналов C:

#include <csignal>
#include <functional>
#include <boost/asio.hpp>

using std::signal;
using boost::asio::io_service;

namespace
{
    std::function<void ()> sighandler;
}

extern "C"
{
    static void handle_signal(int);
}

void handle_signal(int)
{
    // error - undefined behavior
    sighandler();
}

int main()
{
    io_service s;
    sighandler = std::bind(&io_service::stop, &s);
    auto old_sigint = signal(SIGINT, &handle_signal);
    if (old_sigint == SIG_IGN)
        // race condition?  raise SIGINT before I can set ignore back
        signal(SIGINT, SIG_IGN);
    auto old_sigterm = signal(SIGTERM, &handle_signal);
    if (old_sigterm == SIG_IGN)
        // race condition?  raise SIGTERM before I can set ignore back
        signal(SIGTERM, SIG_IGN);
    s.run();
    // reset signals so I can clear reference to io_service
    if (old_sigterm != SIG_IGN)
        signal(SIGTERM, SIG_DFL);
    if (old_sigint != SIG_IGN)
        signal(SIGINT, SIG_DFL);
    // clear reference to io_service, but can I be sure that handle_signal
    // isn't being executed?
    sighandler = nullptr;
    // io_service is destroyed
}
 Timothy00309 янв. 2011 г., 17:26
@Sam добавил комментарий, чтобы показать, что UB, спасибо
 Sam Miller09 янв. 2011 г., 17:08
@ Тимоти, я пометил твой вопрос какc++0x так как похоже, что вы используетеauto ключевое слово.
 Sam Miller09 янв. 2011 г., 16:21
@ Тимоти, вы спрашиваете, как установить обработчик сигнала для сигнала типа SIGINT? Или что делать в этом обработчике сигналов для выключения вашего HTTP-сервера?
 Sam Miller09 янв. 2011 г., 17:02
@ Тимоти, ты не можешь безопасно вызватьio_service::stop из вашего обработчика сигнала, даже если он обернут вboost::function, Это приводит к неопределенному поведению. смотреть намой ответ для получения списка функций, которые вы можете вызвать из обработчика сигнала.
 Timothy00309 янв. 2011 г., 16:53
@Sam добавил пример дизайна csignal

Ответы на вопрос(2)

пример posix HTTP-сервер - это хороший способ корректно завершить работу. Один поток вызываетio_service::run в то время как другой ждет сигнала сsigwait.

В качестве альтернативы вы можете установить обработчик сигнала, но это немного сложнее. Этоочень маленький список асинхронно-безопасных функций вы можете вызывать из обработчика сигнала.

Обработчик процедуры должен быть очень осторожным, поскольку обработка в другом месте была прервана в некоторый произвольный момент. POSIX имеет понятие «безопасная функция». Если сигнал прерывает небезопасную функцию, а обработчик вызывает небезопасную функцию, то поведение не определено. Безопасные функции четко перечислены в различных стандартах.

Список POSIX.1-2003

_Exit () _exit () abort () accept () access () aio_error () aio_return () aio_suspend () alarm () ) clock_gettime () close () connect () create () dup () dup2 () execle () execve () fchmod () fchown () fcntl () fdatasync () fork () fpathconf () fstat () fsync () ftruncate () getegid () geteuid () getgid () getgroups () getpeername () getpgrp () getpid () getppid () getppname () getsockopt () getuid () killu) link () mkdir () mkfifo () open () pathconf () pause () pipe () poll () posix_trace_event () pselect () повышение () read () readlink () recv () recvfrom () recvmsg () rename () rmdir ( ) select () sem_post () send () sendmsg () sendto () setgid () setpgid () setsid () setsockopt () setuid () shutdown () sigaction () sigaddset () sigdelset () () сигнал () sigpause () sigpending () sigprocmask () sigqueue () sigsetue () sigsuspend () sleep () socket () socketpair () stat () symlink () sysconf () tcdrain () tcflow () tcflush () tcgetattr () tcgetpgrp () tcsendbreak () tcsetattr () tcsetpgrp () time () timer_getoverrun () timer_gettime () timer_settime () times () umask () uname () unlink () ).

 Timothy00309 янв. 2011 г., 18:53
Я нашел список функций наэта страница. Однако это зависит от POSIX. Стандарт С говорит что-то другое об этом материале?
 Sam Miller09 янв. 2011 г., 19:19
@ Тимоти, это правильная ссылка, я отредактировал свой ответ. Я не слишком знаком со стандартом C, хотя у меня никогда не было проблем с использованием только функций, перечисленных в справочной странице по сигналам из обработчика сигналов.
Решение Вопроса

7?) Имеетsignal_set класс:

#include <boost/asio/signal_set.hpp>

// Register signal handlers so that the daemon may be shut down. You may
// also want to register for other signals, such as SIGHUP to trigger a
// re-read of a configuration file.
boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
signals.async_wait(
    boost::bind(&boost::asio::io_service::stop, &io_service));

РЕДАКТИРОВАТЬ

В настоящее времявключены в Boost версии 1.47

 Timothy00318 июл. 2011 г., 09:39
Интересно; Asio использует статические переменные для доступа к данным из обработчика сигналов. Это не UB?
 Timothy00318 июл. 2011 г., 12:15
 Kenji30 июл. 2017 г., 22:42
Просто остановив io_service и оставив работу невыполненной, ваше приложение подвергается случайным ошибкам при вызове деструктора io_service.
 CharlesB18 июл. 2011 г., 12:17
@ Timothy003 Thx

Ваш ответ на вопрос