我有一个程序,它使用工作队列来执行任务,并且应该作为守护程序运行。我使用以下代码实现了这一目标:
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;
}
这将关闭原始流程并启动另一个流程。 但是,这导致了我为执行任务而创建的线程在fork之后没有出现的问题。 我的工作队列是全局实例化的,所有其他值和内存地址都正确地复制到子节点,但线程没有。
供参考,这是池类:
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 );
那我怎么解决这个问题呢?
答案 0 :(得分:5)
最简单的方法是不使用全局变量。他们发现的原因(以及更多)都很糟糕。
作为快速和肮脏的解决方法,您可以拥有
extern tpool dbpool(); // function!
在cpp中实现为:
tpool& dbpool() {
static tpool the_instance; // only initialized on first call
return the_instance;
}
这样,只要你不打电话dbpool()
,它就不会被初始化。 (函数local static的初始化自c ++ 11以来一直是线程安全的。)
注意当你在它时,添加一些名称空间,因为在全局名称空间中使用tpool
这样的名称实际上是C ++中的代码味道。
答案 1 :(得分:2)
你知道线程不能在fork()中存活,对吗?将线程分配放入fork()之后调用的方法中没有任何害处。你知道,有时构造函数不是制作东西的最佳位置。当然,避免全局,所以你可以延迟构造,直到fork完成后。
您可能还想查看从控制终端分离守护进程。