многопоточность — c ++ инициализировать глобальный объект ПОСЛЕ форка

У меня есть программа, которая использует рабочую очередь для выполнения задач и должна запускаться как демон. Я добился этого, используя следующий код:

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 );

Так как я могу решить это?

0

Решение

Самый простой способ это не использовать глобалы. Они плохие именно по тем причинам, которые вы обнаружили (и не только).

Как быстрый&грязный обходной путь вы можете иметь

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 ++.

5

Другие решения

Вы знаете, что потоки не выживают fork (), верно? Нет ничего плохого в том, чтобы поместить распределение потоков в метод, который вы вызываете после fork (). Знаешь, иногда конструктор не лучшее место для … создания вещей. Конечно, избегая глобального, так что вы можете отложить конструкцию до тех пор, пока вилка не будет в порядке.

Возможно, вы также захотите отсоединить демон от управляющего терминала.

2