【问题标题】:c++ Initialize global object AFTER forkc ++在fork之后初始化全局对象
【发布时间】:2014-11-20 23:29:51
【问题描述】:

我有一个程序使用工作队列来执行任务,并且应该作为守护进程运行。我一直在使用以下代码实现这一点:

bool seedDaemon() {
        using namespace std;
        int childpid = 0;
        pid_t pid = 0;
        if( ( childpid = fork() ) < 0 ) {
                return false;
        }
        else if( childpid > 0 ){
                exit(0);
        }
        setsid();
        umask(0);
        std::cout<< "[OK]\n";
        close( fileno(stderr) );
        close( fileno(stdout) );
        close( STDIN_FILENO );
        return true;
}

这将关闭原始进程并启动另一个进程。 但是,这导致了我为执行任务而创建的线程在分叉后没有再次出现的问题。 我的工作队列是全局实例化的,所有其他值和内存地址都正确复制到子节点,但线程没有。

作为参考,这里是池类:

pool.h:

#ifndef __POOL_H
#define __POOL_H
class tpool {
        public:
                tpool( std::size_t tpool_size );
                ~tpool();
                template< typename Task >
                void run_task( Task task ){ // add item to the queue
                        io_service_.post( boost::bind( &tpool::wrap_task, this,
                                boost::function< void() > ( task ) ) );
                }
        private:
                boost::asio::io_service io_service_;
                boost::asio::io_service::work work_;
                boost::thread_group threads_;
                boost::mutex mutex_;
                void wrap_task( boost::function< void() > task );
};

extern tpool dbpool; 
#endif

pool.cpp:

#include <boost/asio/io_service.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include "pool.h"
tpool::tpool( std::size_t tpool_size ) : work_( io_service_ ), available_( tpool_size ) {
    for ( std::size_t i = 0; i < tpool_size; ++i ){
        threads_.create_thread( boost::bind( &boost::asio::io_service::run, &io_service_ ) );
    }
}
tpool::~tpool() {
    io_service_.stop();
    try {
        threads_.join_all();
    }
    catch( ... ) {}
}
void tpool::wrap_task( boost::function< void() > task ) {
    // run the supplied task
    try {
        task();
    } // suppress exceptions
    catch( ... ) {
    }
    boost::unique_lock< boost::mutex > lock( mutex_ );
    ++available_;
}
tpool dbpool( 50 );

那我该如何解决呢?

【问题讨论】:

    标签: c++ multithreading boost boost-thread daemons


    【解决方案1】:

    最简单的方法是使用全局变量。由于您发现的原因(以及更多原因),它们很糟糕。

    作为一个快速而肮脏的解决方法,你可以有一个

    extern tpool dbpool();  // function!
    

    在cpp中实现为:

    tpool& dbpool() {
        static tpool the_instance; // only initialized on first call
        return the_instance;
    }
    

    这样,只要你不调用dbpool(),它就不会被初始化。 (从 c++11 开始,函数 local static 的初始化一直是线程安全的)。

    注意在此过程中,请添加一些命名空间,因为在全局命名空间中使用像 tpool 这样的名称实际上是 C++ 中的代码异味。

    【讨论】:

    • 我使用全局变量的原因是它需要对调用它的多个模块和函数是可访问和可见的,并且我会不断收到一个链接器错误,即 dbpool 已被删除但未定义。 >.>
    • @Oblivious12 时间阅读静态初始化命令惨败
    【解决方案2】:

    你知道线程不能在 fork() 中存活,对吧?将线程分配放入您在 fork() 之后调用的方法中没有害处。你知道,有时构造函数不是最好的地方……制作东西。当然,避免全局,这样您就可以将构建延迟到分叉好的之后。

    您可能还想研究将守护程序与控制终端分离。

    【讨论】:

    • 如何从它的控制终端分离一个守护进程?当我今天早上去上班的路上,那个确切的想法 - 创建一个函数来在初始化之后产生线程...... >.>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 2021-10-19
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    相关资源
    最近更新 更多