C ++ Mutexes и STL списки по подклассам - PullRequest
0 голосов
/ 12 мая 2010

Я сейчас пишу многопоточный сервер C ++, используя Poco, и сейчас я нахожусь в точке, где мне нужно хранить информацию о том, какие пользователи подключены, сколько подключений у каждого из них, и, учитывая, что это прокси-сервер, где каждое из этих соединений проходит через.

Для этой цели я создал класс ServerStats, который содержит список STL объектов ServerUser. Класс ServerStats включает функции, которые могут добавлять и удалять объекты из списка, а также находить пользователя в списке и возвращать указатель на него, чтобы я мог получить доступ к функциям-членам внутри любого данного объекта ServerUser в списке.

Класс ServerUser содержит список STL объектов ServerConnection и во многом аналогичен классу ServerStats, в котором содержатся функции для добавления, удаления и поиска элементов в этом списке.

Теперь все вышеперечисленное работает, но я сейчас пытаюсь сделать его потокобезопасным.

Я определил Poco :: FastMutex в классе ServerStats и могу заблокировать / разблокировать его в соответствующих местах, чтобы контейнеры STL не изменялись одновременно с поиском, например. Однако у меня возникла проблема с настройкой взаимных исключений в классе ServerUser, и я получаю следующую ошибку компилятора:

/ корень / росо / Foundation / включить / Poco / Mutex.h: В конструкторе копирования âServerUser :: ServerUser (Const ServerUser &): с SRC / SocksServer.cpp: 185
инстанцируется из oidvoid __gnu_cxx :: new_allocator <_Tp> :: построить (_Tp *, const _Tp &) [with _Tp = ServerUser] â /usr/include/c++/4.4/bits/stl_list.h:464: созданный из âstd :: _ List_node <_Tp> * std :: list <_Tp, _Alloc> :: _ M_create_node (const _Tp &) [with _Tp = ServerUser, _Alloc = станд :: Распределитель] â /usr/include/c++/4.4/bits/stl_list.h:1407: создается из âvoid std :: list <_Tp, _Alloc> :: _ M_insert (std :: _ List_iterator <_Tp>, const _Tp &) [with _Tp = ServerUser, _Alloc = std :: allocator] â /usr/include/c++/4.4/bits/stl_list.h:920: создается из âvoid std :: list <_Tp, _Alloc> :: push_back (const _Tp &) [с _Tp = ServerUser, _Alloc = std :: allocator] â SRC / SocksServer.cpp: 301
созданный отсюда /root/poco/Foundation/include/Poco/Mutex.h:164: ошибка: Кулако :: FastMutex :: FastMutex (Const Poco :: FastMutex &) является частной src / SocksServer.cpp: 185: ошибка: внутри этот контекст в файле включен из /usr/include/c++/4.4/x86_64-linux-gnu/bits/c++allocator.h:34, из /usr/include/c++/4.4/bits/allocator.h:48, из /usr/include/c++/4.4/string:43, из /root/poco/Foundation/include/Poco/Bugcheck.h:44, из /root/poco/Foundation/include/Poco/Foundation.h:147, из /root/poco/Net/include/Poco/Net/Net.h:45, от /root/poco/Net/include/Poco/Net/TCPServerParams.h:43, из src / SocksServer.cpp: 1: /usr/include/c++/4.4/ext/new_allocator.h: В функции-член __gnu_cxx :: new_allocator <_Tp> :: построить (_Tp *, const _Tp &) [with _Tp = ServerUser] â: /usr/include/c++/4.4/ext/new_allocator.h:105: примечание: синтезированный метод âServerUser :: ServerUser (Const ServerUser &) - сначала требуется здесь src / SocksServer.cpp: в глобальном масштабе: src / SocksServer.cpp: 118: предупреждение: âstd :: string getWord (std :: string) â определено, но не используется make: *** [/Root/poco/SocksServer/obj/Linux/x86_64/debug_shared/SocksServer.o] Ошибка 1

Код для классов ServerStats, ServerUser и ServerConnection приведен ниже:

class ServerConnection
{
public:
    bool continue_connection;
    int bytes_in;
    int bytes_out;
    string source_address;
    string destination_address;

    ServerConnection()
    {
        continue_connection = true;
    }

    ~ServerConnection()
    {
    }
};

class ServerUser
{
public:
    string username;
    int connection_count;
    string client_ip;

    ServerUser()
    {
    }

    ~ServerUser()
    {
    }

    ServerConnection* addConnection(string source_address, string destination_address)
    {
        //FastMutex::ScopedLock lock(_connection_mutex);

        ServerConnection connection;
        connection.source_address = source_address;
        connection.destination_address = destination_address;
        client_ip = getWord(source_address, ":");

        _connections.push_back(connection);
        connection_count++;

        return &_connections.back();
    }

    void removeConnection(string source_address)
    {
        //FastMutex::ScopedLock lock(_connection_mutex);

        for(list<ServerConnection>::iterator it = _connections.begin(); it != _connections.end(); it++)
        {
            if(it->source_address == source_address)
            {
                it = _connections.erase(it);
                connection_count--;
            }
        }
    }

    void disconnect()
    {    
        //FastMutex::ScopedLock lock(_connection_mutex);

        for(list<ServerConnection>::iterator it = _connections.begin(); it != _connections.end(); it++)
        {
            it->continue_connection = false;
        }
    }

    list<ServerConnection>* getConnections()
    {
        return &_connections;
    }

private:
    list<ServerConnection> _connections;

    //UNCOMMENTING THIS LINE BREAKS IT:
    //mutable FastMutex _connection_mutex;
};

class ServerStats
{
public:
    int current_users;

ServerStats()
{
    current_users = 0;
}

~ServerStats()
{
}

ServerUser* addUser(string username)
{
    FastMutex::ScopedLock lock(_user_mutex);

    for(list<ServerUser>::iterator it = _users.begin(); it != _users.end(); it++)
    {
        if(it->username == username)
        {
            return &(*it);
        }
    }

    ServerUser newUser;
    newUser.username = username;
    _users.push_back(newUser);
    current_users++;

    return &_users.back();
}

void removeUser(string username)
{
    FastMutex::ScopedLock lock(_user_mutex);

    for(list<ServerUser>::iterator it = _users.begin(); it != _users.end(); it++)
    {
        if(it->username == username)
        {
            _users.erase(it);
            current_users--;
            break;
        }
    }
}

ServerUser* getUser(string username)
{
    FastMutex::ScopedLock lock(_user_mutex);

    for(list<ServerUser>::iterator it = _users.begin(); it != _users.end(); it++)
    {
        if(it->username == username)
        {
            return &(*it);
        }
    }
    return NULL;
}

private:
    list<ServerUser> _users;
    mutable FastMutex _user_mutex;
};

Теперь я никогда не использовал C ++ для проектов такого размера или мьютексов, так что, пожалуйста, будьте проще

Во-первых, кто-нибудь может сказать мне, почему вышеизложенное вызывает ошибку компилятора?

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

1 Ответ

1 голос
/ 12 мая 2010

Проблема в том, что FastMutex не копируется, и, следовательно, ServerUser не копируется. Когда вы вставляете объекты в контейнер STL, они должны быть скопированы. Я думаю, вам придется изменить дизайн ваших классов.

Кроме того, вы должны быть очень осторожны, возвращая указатели на объекты, хранящиеся в контейнере STL, поскольку они могут стать недействительными из-за перестановки объектов при вставке и удалении объектов из контейнера.

...