Yükseltme ASIO kullanarak bir C++ kütüphanesi oluşturdum. Kütüphane hem diş güvenli hem de çatal güvenli olmalıdır. io_service::run()
'u arayarak hizmet zamanlayıcısı iş parçacığına sahiptir. Çatal emniyetini desteklemek için pre_fork, post_fork_parent ve post_fork_child işleyicileri kaydettim. pre_fork()
işleyicisi, _io_service.notify_fork(boost::io_service:fork_prepare()
numaralı telefonu arayarak, post_fork_parent işleyicisi _io_service.notify_fork(boost::asio::io_service::fork_parent)
numaralı telefonu ve post_fork_child çağrılarını _io_service.notify_fork(boost::asio::io_service::fork_child)
çağırır.Asio çatalını nasıl güvenli hale getirebilir
Karşılaştığım sorun, fork()
gerçekleştiği zaman, hizmet zamanlayıcısı iş parçacığı bazı işlemlerin ortasında olabilir ve io_service
nesnesinin veri üyeleri üzerinde kilitlenebilir. Bu nedenle, çocuk işlemi, aynı durumda ve _io_service.notify_fork(boost::asio::io_service::fork_child)
numaralı telefonu aradığımızda post_fork_child() 'da görür, aynı nesne üzerindeki kilidi almayı dener ve bu nedenle süresiz olarak engellenir (kilidin açılması için çocukta bir iplik olmadığı için).
Ben engellenir çocuk süreç, gördüğünüz yığın izlemesi -
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 ????????()
Anlaşılan "dev_poll_reactor" hizmet zamanlayıcısı dizisindeki (bazı bekleyen olayları göndermesiyle gibi görünüyor çünkü) kilitli çatal ne zaman meydana geldiğini soruna neden oluyor.
Sorunu çözmeyi düşünüyorum, hizmet zamanlayıcısı iş parçacığının, fork oluştuğunda herhangi bir işlemin ortasında olmamasını ve pre_fork() işleyicisinde io_service.stop()
numaralı telefonu aramak için bir yol olduğunu garanti etmem gerekiyor. iyi bir çözüm gibi gelmiyor. Kütüphane çatalını güvenli hale getirmek için doğru yaklaşımın ne olduğunu bana bildirir misiniz?
Kod parçacıkları böyle bir şeye benziyor.
/**
* 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);
}
Yükseltme 1.47'yi kullanıyorum ve uygulamayı Solaris i386 üzerinde çalıştırıyorum. Kütüphane ve uygulama stüdyo-12.0 kullanılarak inşa edilmiştir.
Çatal aradıktan sonra çocuğa başka bir şey exec() veya _exit() çağırmayı mı bekliyorsunuz? Eğer öyleyse, yeniden düşünmelisiniz. Değilse, problemi göremiyorum. – janm
Sadece iş parçacığı, komut arabirimi görevleri ve üst-alt işlem için ana iş parçacığı ayırtabilirsiniz. Çataldan sonra, çocukta sadece ana iplik bulunmaktadır. Geri yükleme için iç konfigürasyon verilerini tutabilir ve çocuk süreçlerinde gerekli iplikleri oluşturabilirsiniz. Bu şekilde temiz bir kapsülleme sağlar ve kilitleme ihtiyaçlarını önler. –
İki proje için boost :: asio kullanmayı denedikten sonra, artırma kullanmamanın daha iyi olduğuna inanıyorum. Basit örneklerde bile parçalara ayırır. Karmaşık şablon yapısının, anlaşılması zor ve muhtemel bir sebebi bile anlamlı bir şekilde anlamak ve anlamak imkansızdır. – wallyk