2010-05-12 59 views
0

我目前正在編寫一個使用Poco的多線程C++服務器,現在我需要保留哪些用戶連接的信息,每個連接有多少個連接,以及因爲它是一個代理服務器,其中每個連接都通過代理進行連接。跨子類的C++互斥鎖和STL列表

爲此,我創建了一個ServerStats類,它包含一個ServerUser對象的STL列表。 ServerStats類包括可以從列表中添加和刪除對象以及在列表中找到用戶的函數,並返回指向它們的指針,以便我可以訪問列表中任何給定的ServerUser對象內的成員函數。

ServerUser類包含一個ServerConnection對象的STL列表,非常類似於ServerStats類,它包含添加,刪除和查找此列表中的元素的函數。

現在所有上述工作,但我現在試圖使它線程安全。

我已經在ServerStats類中定義了一個Poco :: FastMutex,並且可以在適當的位置鎖定/解鎖它,以便STL容器在搜索時不會同時被修改。但是我有一個問題ServerUser類中建立互斥體,並正在以下編譯器錯誤:

/root/poco/Foundation/include/Poco/Mutex.h: In copy constructor âServerUser::ServerUser(const ServerUser&)â: src/SocksServer.cpp:185:
instantiated from âvoid __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = ServerUser]â /usr/include/c++/4.4/bits/stl_list.h:464: instantiated from âstd::_List_node<_Tp>* std::list<_Tp, _Alloc>::_M_create_node(const _Tp&) [with _Tp = ServerUser, _Alloc = std::allocator]â /usr/include/c++/4.4/bits/stl_list.h:1407: instantiated from â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: instantiated from âvoid std::list<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = ServerUser, _Alloc = std::allocator]â src/SocksServer.cpp:301:
instantiated from here /root/poco/Foundation/include/Poco/Mutex.h:164: error: âPoco::FastMutex::FastMutex(const Poco::FastMutex&)â is private src/SocksServer.cpp:185: error: within this context In file included from /usr/include/c++/4.4/x86_64-linux-gnu/bits/c++allocator.h:34, from /usr/include/c++/4.4/bits/allocator.h:48, from /usr/include/c++/4.4/string:43, from /root/poco/Foundation/include/Poco/Bugcheck.h:44, from /root/poco/Foundation/include/Poco/Foundation.h:147, from /root/poco/Net/include/Poco/Net/Net.h:45, from /root/poco/Net/include/Poco/Net/TCPServerParams.h:43, from src/SocksServer.cpp:1: /usr/include/c++/4.4/ext/new_allocator.h: In member function âvoid __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = ServerUser]â: /usr/include/c++/4.4/ext/new_allocator.h:105: note: synthesized method âServerUser::ServerUser(const ServerUser&)â first required here src/SocksServer.cpp: At global scope: src/SocksServer.cpp:118: warning: âstd::string getWord(std::string)â defined but not used make: *** [/root/poco/SocksServer/obj/Linux/x86_64/debug_shared/SocksServer.o] Error 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

問題是FastMutex不可複製,因此ServerUser不可複製。將對象插入STL容器時,必須將其複製。我認爲你將不得不改變你的課程設計。另外,你必須非常小心地返回指向存儲在STL容器中的對象的指針,因爲當你從容器中插入和移除東西時,它們可能因爲對象被重新組合而變得無效。

+0

@Genesis:你可能會考慮讓互斥體成爲一個靜態成員,除非有機會讓你的線程串行化。 – stefaanv 2010-05-12 08:54:03

+0

他可以在容器中存儲(智能)對象的指針,例如boost/tr1 :: shared_ptr,例如 – Nikko 2010-05-12 09:21:09

+0

@Nikko:是的,shared_ptr可以工作,但是這是否是一個好選擇必須與這些方法一起考慮類將與系統的其他部分一起工作(並且我提到的返回指針的問題應該同時考慮)。我並不十分了解其他代碼,以便在此提出解決方案。 – 2010-05-12 09:47:47