gpt4 book ai didi

c++ - 如何使 boost asio 前叉安全

转载 作者:IT老高 更新时间:2023-10-28 21:48:24 25 4
gpt4 key购买 nike

我已经使用 boost ASIO 构建了一个 C++ 库。该库需要既是线程安全的又是 fork 安全的。它有服务调度线程,调用io_service::run()。为了支持 fork 安全,我注册了 pre_fork、post_fork_parent 和 post_fork_child 处理程序。 pre_fork() 处理程序,调用 _io_service.notify_fork(boost::io_service:fork_prepare(),post_fork_parent 处理程序调用 _io_service.notify_fork(boost::asio::io_service::fork_parent) 和 post_fork_child 调用 _io_service.notify_fork(boost::asio::io_service::fork_child)

我面临的问题是,当 fork() 发生时,服务调度程序线程可能处于某些操作的中间,并且可能已经获得了 io_service< 数据成员的锁定对象。因此,当我们调用 _io_service.notify_fork(boost::asio::io_service::fork_child) 时,子进程在 post_fork_child() 中看到它们处于相同的状态,它试图获取对相同的对象,因此被无限期地阻塞(因为子进程中没有线程来释放解锁)。

我在子进程中看到的被阻塞的堆栈跟踪是-

fffffd7ffed07577 lwp_park (0, 0, 0) 
fffffd7ffecffc18 mutex_lock_internal () + 378
fffffd7ffecfffb2 mutex_lock_impl () + 112
fffffd7ffed0007b mutex_lock () + b
fffffd7fff26419d __1cFboostEasioGdetailLscoped_lock4n0CLposix_mutex__2t5B6Mrn0D__v_ () + 1d
fffffd7fff2866a2 __1cFboostEasioGdetailQdev_poll_reactorMfork_service6Mn0BKio_serviceKfork_event__v_ () + 32
fffffd7fff278527 __1cFboostEasioGdetailQservice_registryLnotify_fork6Mn0BKio_serviceKfork_event__v_ () + 107
fffffd7fff27531c __1cDdesGtunnelQServiceSchedulerPpost_fork_child6M_v_ () + 1c
fffffd7fff29de24 post_fork_child () + 84
fffffd7ffec92188 _postfork_child_handler () + 38
fffffd7ffecf917d fork () + 12d
fffffd7ffec172d5 fork () + 45
fffffd7ffef94309 fork () + 9
000000000043299d main () + 67d
0000000000424b2c ???????? ()

显然,当 fork 发生导致问题时,服务调度程序线程中的“dev_poll_reactor”被锁定(因为它似乎正在调度一些待处理的事件)。

我认为要解决这个问题,我需要确保在 fork 发生时服务调度程序线程不在任何处理的中间,并且保证这一点的一种方法是调用 io_service.stop() 在 pre_fork() 处理程序中,但这听起来不是一个好的解决方案。您能否让我知道使库叉安全的正确方法是什么?

代码片段看起来像这样。

/** 
* Combines Boost.ASIO with a thread for scheduling.
*/
class ServiceScheduler : private boost::noncopyable
{
public :
/// The actual thread used to perform work.
boost::shared_ptr<boost::thread> _service_thread;

/// Service used to manage async I/O events
boost::asio::io_service _io_service;

/// Work object to block the ioservice thread.
std::auto_ptr<boost::asio::io_service::work> _work;
...
};

/**
* CTOR
*/
ServiceScheduler::ServiceScheduler()
: _io_service(),
_work(std::auto_ptr<boost::asio::io_service::work>(
new boost::asio::io_service::work(_io_service))),
_is_running(false)
{
}

/**
* Starts a thread to run async I/O service to process the scheduled work.
*/
void ServiceScheduler::start()
{
ScopedLock scheduler_lock(_mutex);
if (!_is_running) {
_is_running = true;
_service_thread = boost::shared_ptr<boost::thread>(
new boost::thread(boost::bind(
&ServiceScheduler::processServiceWork, this)));
}
}

/**
* Processes work passed to the ASIO service and handles uncaught
* exceptions
*/
void ServiceScheduler::processServiceWork()
{
try {
_io_service.run();
}
catch (...) {
}
}

/**
* Pre-fork handler
*/
void ServiceScheduler::pre_fork()
{
_io_service.notify_fork(boost::asio::io_service::fork_prepare);
}

/**
* Post-fork parent handler
*/
void ServiceScheduler::post_fork_parent()
{
_io_service.notify_fork(boost::asio::io_service::fork_parent);
}

/**
* Post-fork child handler
*/
void ServiceScheduler::post_fork_child()
{
_io_service.notify_fork(boost::asio::io_service::fork_child);
}

我正在使用 boost 1.47 并在 Solaris i386 上运行该应用程序。该库和应用程序是使用 studio-12.0 构建的。

最佳答案

asio代码规定,当io_service代码中有代码时,notify_fork()不起作用。

This function must not be called while any other io_service function, or any function on an I/O object associated with the io_service, is being called in another thread. It is, however, safe to call this function from within a completion handler, provided no other thread is accessing the io_service.

这似乎包括 run 或与库关联的任何 IO。我认为您的 pre_fork 处理应该重置一个工作项。

例如来自 boost documentation

boost::asio::io_service io_service;
auto_ptr<boost::asio::io_service::work> work(
new boost::asio::io_service::work(io_service));
...
pre_fork() {
work.reset(); // Allow run() to exit.
// check run has finished...
io_service.notify_fork(...);
}

仍需谨慎

  1. 确保在 post_fork() 完成之前不调用 run()
  2. 确保为下一次 run
  3. 创建新的 work 对象
  4. 正确同步以确保发现 run 终止。

关于c++ - 如何使 boost asio 前叉安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9362258/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com