我正在使用套接字制作一个多线程的c++应用程序。
换句话说,我有很多对象要关闭(例如,我的服务器套接字,关闭我的线程等)。
我通常从main()函数的末尾关闭所有内容,但当应用程序用户按Ctrl+C时,我无法以适当的方式关闭所有内容
顺便说一下,我可以将所有示例都保存为static
,并在静态函数中关闭它们以处理SIGINT
信号,但这对我来说听起来不太合适,因为我有很多示例要关闭。
我正准备用sigaction或signal捕获我所有的示例,但它无法编译。
signal(SIGINT, [myInstance](int) { myInstance.close() };
实际上,向匿名函数捕获添加示例会改变签名,使其不再是函数。
有没有其他合适的方法来达到我的目的?
4条答案
按热度按时间6ss1mwsb1#
用事件驱动核心编写程序。
这个事件驱动的核心通常花费时间什么也不做,等待新的事件。
当你收到SIGINT时,只需要通知事件驱动内核信号已经到达,然后让它干净地关闭并退出main。
xmq68pz92#
我假设您使用的是Linux(或其他POSIX系统)。
然后仔细阅读signal(7)和signal-safety(7)和pthreads(7)(在Linux C++11上
std::thread
-s是在pthreads上实现的)。请注意,信号和线程在一起并不好用。
一个众所周知的技巧是在初始化时设置一些pipe(7)(to self),并在该管道上设置一些信号处理程序write(2),然后让event loop处理该管道输入并对其进行poll(2)-ing,Qt甚至在其Calling Qt Functions From Unix Signal Handlers页面中也建议并解释了这一点。
您可能希望使用sigaction(2)(而不是signal(2)),并且需要提供一个原始函数(而不是
std::function
或lambda表达式)-最好是extern "C"
函数(以确保编译器对信号处理程序使用C调用约定)。您可以考虑(对于
SIGINT
和SIGTERM
)使用Linux特定的signalfd(2)。您可能更喜欢避免处理信号,而使用其他一些inter-process communication工具(可能是socket(7)之上的JSONRPC,或者可能是HTTP,通过使用一些HTTP服务器库,如libonion或Wt,并使您的应用程序成为web application)来要求您的程序温和地终止。
ltskdhd13#
首先,看看boost::asio,如果你还没有的话。它是一个很棒的库,可以让你更容易地建立网络。至于你的问题:面向对象的设计可能会对你有很大帮助。不要直接使用socket API。但是如果没有关于你的应用程序或背景的任何更具体的信息(例子,片段),很难推荐任何具体的东西。下面是一些想法:
捕获SIGINT然后终止应用程序实际上与在main函数中使用while循环等待按键没有太大区别,它只是终止应用程序的另一种方式。
编写服务器类。编写连接类。在堆上示例化新连接并使用shared_ptr(使用make_shared)。保留活动连接对象的列表。为服务器类编写一个shutdown方法,用于迭代这些对象并关闭它们。在main中为每个侦听套接字示例化一个服务器对象(这样您就可以轻松地拥有一个双栈应用程序,一个侦听IP4套接字,另一个侦听IP6套接字)。为每个服务器和每个连接分别配置一个线程(注意:当同时具有数百或数千个活动连接时,这是缓慢的)。
研究Boost::AIO的例子。有一些很棒的例子可以做你想做的事情。另外,Boost::AIO可以作为“事件驱动核心”工作,正如另一个答案正确地建议的那样。
尽可能使用RAII(资源获取即初始化)。
当您捕获SIGINT时,只需调用server::shutdown。
tv6aics14#