Tôi đã xây dựng một thư viện C++ sử dụng ASIO tăng cường. Thư viện cần phải vừa an toàn vừa an toàn. Nó có chuỗi lịch trình dịch vụ, gọi là io_service::run()
. Để hỗ trợ tính năng an toàn ngã ba, tôi đã đăng ký các trình xử lý pre_fork, post_fork_parent và post_fork_child. Trình xử lý pre_fork()
, gọi _io_service.notify_fork(boost::io_service:fork_prepare()
, các cuộc gọi xử lý post_fork_parent _io_service.notify_fork(boost::asio::io_service::fork_parent)
và các cuộc gọi post_fork_child _io_service.notify_fork(boost::asio::io_service::fork_child)
.Làm thế nào để tăng an toàn asio fork
Sự cố mà tôi đang gặp phải khi xảy ra sự cố fork()
, chuỗi lịch trình dịch vụ có thể đang ở giữa một số thao tác và có thể đã bị khóa trên các thành viên dữ liệu của đối tượng io_service
. Vì vậy, quá trình con thấy chúng trong cùng một trạng thái và trong post_fork_child() khi chúng ta gọi _io_service.notify_fork(boost::asio::io_service::fork_child)
nó cố gắng để có được khóa trên cùng một đối tượng và do đó bị chặn vô thời hạn (vì không có thread trong con để phát hành mở khóa).
Các vết đống tôi thấy trong quá trình đứa trẻ, mà bị chặn, là -
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 ????????()
Rõ ràng "dev_poll_reactor" bị khóa (vì nó có vẻ được cử một số sự kiện đang treo) trong thread dịch vụ lên lịch khi ngã ba đã xảy ra gây ra vấn đề.
Tôi nghĩ rằng để giải quyết vấn đề, tôi cần đảm bảo rằng chuỗi lịch trình dịch vụ không ở giữa bất kỳ quá trình xử lý nào khi ngã ba xảy ra và một cách để đảm bảo sẽ gọi io_service.stop()
trong trình xử lý pre_fork() nhưng không Âm thanh như một giải pháp tốt. Bạn có thể vui lòng cho tôi biết phương pháp phù hợp để làm cho nĩa thư viện có an toàn không?
Đoạn mã trông giống như thế này.
/**
* 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);
}
Tôi đang sử dụng tăng 1,47 và chạy ứng dụng trên Solaris i386. Thư viện và ứng dụng được xây dựng bằng cách sử dụng studio-12.0.
Bạn có dự định thực hiện bất kỳ lệnh gọi hàm exec() hoặc _exit() nào khác sau khi bạn gọi cho ngã ba không? Nếu vậy, bạn nên xem xét lại. Nếu không, tôi không thấy vấn đề. – janm
Bạn có thể đặt chủ đề chính cho chỉ quản trị, các tác vụ giao diện lệnh và xử lý cha-con. Sau ngã ba, chỉ có chủ đề chính tồn tại ở trẻ. Bạn có thể giữ một dữ liệu cấu hình nội bộ để khôi phục và tạo các luồng cần thiết trong tiến trình con. Bằng cách này, đảm bảo đóng gói sạch sẽ và tránh nhu cầu khóa. –
Sau khi cố gắng sử dụng boost :: asio cho hai dự án, tôi đã đạt đến kết luận tốt hơn là không nên sử dụng boost. Nó phân biệt ngay cả trên các ví dụ đơn giản. Cấu trúc khuôn mẫu phức tạp của nó là quá khó hiểu và không thể có nghĩa là bước qua và xác định ngay cả một nguyên nhân có thể xảy ra. – wallyk