2012-01-25 2 views
1

Я пишу многопоточный сервер с помощью boost::asio (для сокетов), boost::thread (для нарезания резьбы), libconfig++ (для файлов конфигурации чтения) и protocol buffers (для реализации протокола).C++ частный доступ к членам других классов

Сервер использует более или менее этот маршрут: main() -> создает объект приложения -> запускает объект приложения. Приложение загружает файл конфигурации, а затем создает объект сервера (который передается классом конфигурации как const). Объект сервера настраивает себя и связывает порт, начинает принимать, бла. Всякий раз, когда обнаруживается новый клиент, сервер создает новый объект Client, а затем создает поток, выполняющий обработчик соединения клиента.

Все это объясняет, что файл конфигурации загружается из моего класса приложения, а затем передается до моего класса Client. Это не должно создавать каких-либо проблем, если объект libconfig передавался непосредственно всем клиенту, но, как мы все знаем, многопоточность подразумевает, что память повреждается при одновременном доступе двумя или более потоками.

The way to solve this was discussed in other post и закончил с внедрением обертки, которая автоматически решает проблему мьютекса.

Волшебный класс

app_config.h

#ifndef _APP_CONFIG_H_ 
#define _APP_CONFIG_H_ 1 

#include <boost/shared_ptr.hpp> 
#include <boost/thread/mutex.hpp> 
#include <boost/thread/locks.hpp> 
#include <boost/noncopyable.hpp> 
#include <libconfig.h++> 
#include <string> 

namespace BBCP { 
    namespace App { 

class ConfigLock; 

class Config { 
public: 
    friend class BBCP::App::ConfigLock; 

    Config(std::string const &file) : 
     cfg(new libconfig::Config()), 
     mutex(new boost::mutex()) 
    { 
     cfg->readFile(file.c_str()); 
    } 

private: 
    boost::shared_ptr<libconfig::Config> cfg; 
    boost::shared_ptr<boost::mutex> mutex; 
}; 

class Server; 
class Client; 

class ConfigLock : boost::noncopyable { 
public: 
    ConfigLock(BBCP::App::Config const &wrapper) : 
     cfg(wrapper.cfg), 
     mutex(wrapper.mutex), 
     lock(new LockType(*mutex)) 
    { } 

    libconfig::Config &get() throw() { return *cfg; }; 
private: 
    boost::shared_ptr<libconfig::Config> cfg; 
    boost::shared_ptr<boost::mutex> mutex; 

    typedef boost::lock_guard<boost::mutex> LockType; 
    boost::shared_ptr<LockType> lock; 
}; 

    } 
} 

#endif 

Для ленивых людей, этот класс состоит из ... ну, два класса (парадокс?): BBCP::App::Config и BBCP::App::ConfigLock. BBCP::App::Config просто загружает файл, а BBCP::App::ConfigLock принимает BBCP::App::Config в качестве аргумента, а затем блокирует mutex BBCP::App::Config. После того, как замок был создан, один вызывает BBCP::App::ConfigLock::get, который возвращает ссылку на объект libconfig::Config !.

Проблема

Ну:

server.cpp:

void BBCP::App::Server::startAccept() { 
    newClient.reset(new BBCP::App::Client(io_service, config_wrapper)); 
    acceptor.async_accept(newClient->getSocket(), boost::bind(&BBCP::App::Server::acceptHandler, this, boost::asio::placeholders::error)); 
} 

Эта функция создает новый объект клиента, загруженный с boost::asio::io_service объекта и BBCP::App::Config объекта.

server.cpp

void BBCP::App::Server::acceptHandler(boost::system::error_code const &e) { 
    if (!acceptor.is_open()) { 
     // ARR ERROR! 
     return; 
    } 

    if (!e) { 
     client_pool.create_thread(*newClient); 
    } 
    else { 
     // HANDLE ME ERROR 
     throw; 
    } 

    startAccept(); 
} 

Эта функция создает новый поток или (пока не реализовано) ошибок в случае ... ну, ошибки, а затем начинается снова принять петлю.

код

Клиент в основном не имеет значения до этой части:

client.cpp:

void BBCP::App::Client::parseBody() { 
    BBCP::Protocol::Header header; 
    BBCP::Protocol::Hello hello; 
    boost::scoped_ptr<BBCP::App::ConfigLock> lock; 
    libconfig::Config *cfg; 

    (...) 

    switch ((enum BBCP::Protocol::PacketType)header.type()) { 
     case BBCP::Protocol::HELLO: 
      (...) 

      // config_wrapper is a private variable in the client class! 
      lock.reset(new BBCP::App::ConfigLock(config_wrapper)); 

      // ARRRRRRR HERE BE DRAGOONS!! 
      *cfg = lock->get(); 

      (...) 

      lock.reset(); 
      break; 
     (...) 

    } 

    (...) 
} 

Ну, по правде говоря, я не ожидал такого рода ошибки:

/usr/include/libconfig.h++: In member function ‘void BBCP::App::Client::parseBody()’: 
/usr/include/libconfig.h++:338:13: error: ‘libconfig::Config& libconfig::Config::operator=(const libconfig::Config&)’ is private 
client.cpp:64:30: error: within this context 
client.cpp:71:21: error: request for member ‘exists’ in ‘cfg’, which is of non-class type ‘libconfig::Config*’ 
client.cpp:77:51: error: request for member ‘lookup’ in ‘cfg’, which is of non-class type ‘libconfig::Config*’ 

Но вот оно, и мне нужно как-то его решить :(.Я попытался сделать BBCP::App::Client другой класс BBCP::App::ConfigLock, но потом пошло как:

In file included from ../include/app_config.h:4:0, 
       from ../include/app_main.h:6, 
       from main.cpp:18: 
../include/app_client.h:15:53: error: ‘BBCP::App::Config’ has not been declared 
In file included from ../include/app_config.h:4:0, 
       from ../include/app_main.h:6, 
       from main.cpp:18: 
../include/app_client.h:32:5: error: ‘Config’ in namespace ‘BBCP::App’ does not name a type 
In file included from ../include/app_config.h:4:0, 
       from ../include/app_main.h:6, 
       from main.cpp:18: 
../include/app_client.h: In constructor ‘BBCP::App::Client::Client(boost::asio::io_service&, const int&)’: 
../include/app_client.h:15:120: error: class ‘BBCP::App::Client’ does not have any field named ‘config_wrapper’ 

И тогда я пошел, как Ие, так что я просто сдался и приехал сюда, еще раз искал какое-то über C++ гуру hackz0r года помогать и ругать за совершение такого промаха, как пытаться получить доступ к частным членам другого класса.

+0

Я не понимаю эту часть: «Я попытался сделать« BBCP :: App :: Client »класс друзей« BBCP :: App :: ConfigLock ». Сообщение об ошибке жалуется на функцию члена 'BBCP :: App :: Client', пытаясь получить доступ к приватному методу' libconfig :: Config' (перегруженному оператору присваивания), поэтому для подхода класса friend для работы, Вам нужно сделать 'BBCP :: App :: Client' класс друзей' libconfig :: Config'? – ruakh

+1

Небольшой совет, переименуйте '_APP_CONFIG_H_'. В §17.4.3.2.1 говорится: «Каждое имя, содержащее двойной знак подчеркивания (_ _) или начинающийся с символа подчеркивания, за которым следует заглавная буква (2.11), зарезервировано для реализации для любого использования.» – jweyrich

+0

Многопоточность * только для чтения * доступ к переменная не является проблематичной. Я не знаю, планируете ли вы изменить объект конфигурации во время работы программы, но если вы не все, то будет проще. Кроме того, вам нужно потратить некоторое время на разработку (почему объект конфигурации не публично копируется) и узнать, что компилятор пытается рассказать вам в сообщениях об ошибках, так как они помогают вам разобраться в проблемах. –

ответ

0

Вы, вероятно, хотели сохранить указатель на объект конфигурации в cfg вместо создания копии (и разыменования неинициализированного указателя):

cfg = &local->get(); 
1

Первое является выяснение того, если вы собираетесь в праве направлении, и следующий шаг туда добирается.

Почему оператор присваивания типа Config является приватным? По умолчанию сгенерированный оператор присваивания является общедоступным, поэтому, если он был объявлен как закрытый, есть вероятность, что есть причина, по которой объект не будет скопирован, или же вы должны сделать его общедоступным, и проблема больше не будет проблемой ,

С вашей конкретной проблемой после добавления объявления друга, кажется, указывается, что вы пропустили, включая заголовок, в котором объявлен/определен тип Config. И еще есть некоторые ошибки в коде (член, который не был определен - результат предыдущей ошибки?), Или в исходном коде, пытающемся получить доступ к объекту, указанному указателем без разыменования его ...

+0

Идея состояла в том, чтобы не копировать объект, а хранить указатель на объект. Тем не менее, я не знаю, почему оператор копирования был закрыт. –

Смежные вопросы