【发布时间】:2020-04-22 16:52:27
【问题描述】:
在 Linux GPLv3+ 项目 https://github.com/bstarynk/helpcovid/(多线程、C++17、Web 服务器应用程序)中提交 b616defc5e54ba869。需要能够优雅地终止这样的 Web 服务器(使用 libpqxx 与一些 PostGreSQL 数据库交互)。所以issue#35。
我确实读过signal(7) 和signal-safety(7) 和signalfd(2)。我知道criticisms against signalfd。
我在几个文件描述符上有一个单一的背景 C++ std::thread poll(2)-ing。请参见文件hcv_background.cc,其中hcv_start_background_thread 函数从文件hcv_main.cc 中的main 函数调用,并且创建的std::thread 运行hcv_background_thread_body 函数(一个执行poll(2) 的事件循环......)
所以hcv_start_background_thread 有:
{
sigset_t sigmaskbits;
memset (&sigmaskbits, 0, sizeof(sigmaskbits));
sigemptyset(&sigmaskbits);
sigaddset(&sigmaskbits, SIGTERM);
sigaddset(&sigmaskbits, SIGHUP);
sigaddset(&sigmaskbits, SIGXCPU);
sigaddset(&sigmaskbits, SIGPIPE);
/// http://man7.org/linux/man-pages/man2/sigprocmask.2.html
if (sigprocmask(SIG_UNBLOCK, &sigmaskbits, nullptr))
HCV_FATALOUT("hcv_start_background_thread: sigprocmask failure");
HCV_DEBUGOUT("hcv_start_background_thread sigprocmask done");
hcv_bg_signal_fd = signalfd(-1, &sigmaskbits, SFD_NONBLOCK | SFD_CLOEXEC);
if (hcv_bg_signal_fd < 0)
HCV_FATALOUT("hcv_start_background_thread: signalfd failure");
HCV_DEBUGOUT("hcv_start_background_thread hcv_bg_signal_fd=" << hcv_bg_signal_fd);
}
hcv_background_thread_body 函数有一个事件循环在做
while (!hcv_should_stop_bg_thread.load())
{
struct pollfd polltab[4];
memset(&polltab, 0, sizeof(polltab));
polltab[0].fd = hcv_bg_event_fd;
polltab[0].events = POLL_IN;
polltab[1].fd = hcv_bg_signal_fd;
polltab[1].events = POLL_IN;
polltab[1].fd = hcv_bg_timer_fd;
polltab[1].events = POLL_IN;
HCV_DEBUGOUT("hcv_background_thread_body before poll");
int nbfd = poll(polltab, 3,
hcv_debugging.load()?(2*HCV_BACKGROUND_TICK_TIMEOUT):HCV_BACKGROUND_TICK_TIMEOUT);
之后在同一个事件循环中
if (nbfd>0) /* some file descriptor is readable */
{
HCV_DEBUGOUT("hcv_background_thread_body: after poll nbfd:" << nbfd);
if ((polltab[0].revents & POLL_IN) && polltab[0].fd == hcv_bg_event_fd)
{
int64_t evrk=0;
HCV_DEBUGOUT("hcv_background_thread_body pollable hcv_bg_event_fd="
<< hcv_bg_event_fd);
int byrd = read (hcv_bg_event_fd, &evrk, sizeof(evrk));
if (byrd==sizeof(evrk))
{
HCV_DEBUGOUT("hcv_background_thread_body: got " << evrk
<< " from hcv_bg_event_fd=" << hcv_bg_event_fd);
hcv_bg_do_event(evrk);
}
else
HCV_SYSLOGOUT(LOG_WARNING,
"hcv_background_thread_body read hcv_bg_event_fd#" <<hcv_bg_event_fd << " failed, byrd=" << byrd);
};
if ((polltab[1].revents & POLL_IN) && polltab[1].fd == hcv_bg_signal_fd)
{
HCV_DEBUGOUT("hcv_background_thread_body pollable hcv_bg_signal_fd="
<< hcv_bg_signal_fd);
struct signalfd_siginfo signalinfo;
memset (&signalinfo, 0, sizeof(signalinfo));
int byrd = read(hcv_bg_signal_fd, &signalinfo, sizeof(signalinfo));
if (byrd < 0)
HCV_FATALOUT("hcv_background_thread_body: failed read of hcv_bg_signal_fd="
<< hcv_bg_signal_fd);
else if (byrd != sizeof(signalinfo))
// should never happen... see signalfd(2)
HCV_FATALOUT("hcv_background_thread_body: corrupted read of hcv_bg_signal_fd="
<< hcv_bg_signal_fd << ", byrd=" << byrd);
HCV_DEBUGOUT("hcv_background_thread_body: got signalinfo #" << signalinfo.ssi_signo
<< " from hcv_bg_signal_fd=" << hcv_bg_signal_fd);
if (signalinfo.ssi_signo == SIGTERM)
{
HCV_SYSLOGOUT(LOG_NOTICE, "hcv_background_thread_body got SIGTERM at "
<< (hcv_monotonic_real_time() - hcv_monotonic_start_time)
<< " elapsed seconds");
hcv_process_SIGTERM_signal();
hcv_should_stop_bg_thread.store (true);
}
但hcv_process_SIGTERM_signal 从未被调用。
我做错了什么?
【问题讨论】:
-
“我做错了什么?” - 用 C++ 编写 Web 应用程序框架?这可能是一个有趣的智力练习,但如果您的目标是提供有用的东西,那么提供一些东西 是有价值的,这样您就可以学习和迭代它。选择许可证和所有这些都很棒,但它可以每秒处理零个请求,直到用户可以部署(并认为“部署到 Heroku”按钮而不是 Linux 系统管理员)并尝试一下!
-
好吧,其他小伙伴不知道ocsigen,我不知道也不想学PHP或Python。有几个人建议用 C++ 编写 Web 应用程序。
-
我并不是说这不可能,或者人们不想这样做(……十年前),只是如果你想做的实际上是帮助人们,那么 生产中的软件胜过无休止的研究项目。
-
它既不是生产也不是研究项目。
标签: linux multithreading signals c++17