2014-09-05 82 views
0

我正在做一個簡單的服務器應用程序,你可以有多個連接,每個連接是一個單一的線程。這是我想它看起來像(它不工作)的例子中,有線程的集合,每個線程實例化類連接物:C++對象和線程

class connection{}; 

class server{ 
std::vector<std::thread> active_connections; 
public: 
    void listen() {active_connections.push_back(std::thread(connection));} 
}; 

我一直在尋找解決方案,但我能找到的最好的是一些成員函數線程。溶液變成非常錯誤的,當我測試它,例如:

class connection{}; 

class server{ 
std::vector<std::thread> active_connections; 
public: 
    void new_connection() { ... } 
    void listen() { 
     active_connections.push_back(std::thread(&server::new_connection,this)); } 
    }; 

的信息是:錯誤:使用刪除功能「的std ::螺紋::線程(常量的std ::線程&)的。 這是否意味着std :: thread類想要複製服務器類?我不太瞭解C++,所以請不要燃燒,我只是問。

謝謝!

編輯:

這是發生這種情況:

void server::do_listen() 
{ 
    int addr_size = sizeof(sockaddr_in); 
    sockaddr_in client_sock; 
    connection_info cn_info; 

    while(true) 
    { 
     int csock; 
     if((csock = accept(server_sock, (sockaddr*)&client_sock, (socklen_t*)&addr_size)) != -1) 
     { 
      printf("Incomming connection from %s.\n", inet_ntoa(client_sock.sin_addr)); 
      memset(&cn_info,0, sizeof(connection_info)); 
      cn_info.sock_addr = client_sock; 
      cn_info.sock = csock; 
      std::thread thr(&server::new_connection, *this, cn_info); 
      thr.join(); 
     } 

    } 
} 

這是迄今爲止。 server::new_connection()仍然是空的。

+0

可能的重複[Error C2280:'std :: thread :: thread(const std :: thread&)':試圖引用已刪除的函數](http://stackoverflow.com/questions/20723566/error- c2280-stdthreadthreadconst-stdthread-attempting-to-reference) – duDE 2014-09-05 12:20:38

+3

這意味着某事正試圖複製一個不可複製的'thread'對象。但是你發佈的代碼並沒有這樣做,並且一旦我修復了顯而易見的錯誤('active_connections'應該是一個變量,而不是一個函數)就會編譯。請發佈一個最簡單的測試用例,演示您遇到的問題。 – 2014-09-05 12:22:16

回答

3

的問題是在這裏:

std::thread thr(&server::new_connection, *this, cn_info); 
             ^

要綁定的服務器對象的副本;這是不可複製的,因爲它包含(一個容器)不可複製的對象。相反,綁定一個指針:

std::thread thr(&server::new_connection, this, cn_info); 

有些人可能會發現lambda更具可讀性;這抓住了this指針和cn_info按值:

std::thread thr([=]{new_connection(cn_info);}); 

這樣的評註中提到,你可以通過綁定一個reference wrapper混淆的解決方案:

std::thread thr(&server::new_connection, std::ref(*this), cn_info); 

但我更願意刪除,而不是增加,複雜性在可能的情況。

+0

+1但我們還要提到'std :: ref'和'std :: cref' http://en.cppreference.com/w/cpp/utility/functional/ref – Peter 2014-09-05 12:41:04

+0

是的,修復了這個問題,謝謝! – user3357962 2014-09-05 12:46:55

+1

@彼得:如果你這麼說。這只是與此問題有關的外圍因素,除非你對不必要的複雜性有迷戀,否則這裏不需要,但是我已經提到過它。 – 2014-09-05 12:50:46

2

Does that mean the std::thread class wants to copy the server class?

不,這意味着一個std::thread的副本某處做,但那是禁止在NonCopyablestd::thread(注意構造函數列表中thread(const thread&) = delete;)。

您應該刪除任何執行thread副本的代碼。您發佈的內容不會執行此類複製。

,其中一份是由「幕後」的一個例子是在一個線程變量的載體的push_back,即:

std::thread myThread; 
myVector.push_back(myThread); 

在您的代碼:

active_connections.push_back(std::thread(&server::new_connection,this)); 

你'推回一個臨時的,它不會被複制,但移動到矢量。

+1

好的,這不是正確的措辭。我的意思是'push_back' op('push_back(std :: thread(&server :: new_connection,this));')沒有複製。將編輯。 – JBL 2014-09-05 12:47:17

0

更多設計問題給您作者:

您爲一個連接創建一個線程。如果你有十個連接,你有十個線程。但是如果你想要處理10000個連接,你會怎麼做?我不確定你的操作系統是否喜歡它。

一個更好的連接處理方法 - 僅在我看來 - 將是如果你只有N個線程處理你的網絡連接。如果您的電腦有例如六個核心,你可以花費一個,兩個或更多的線程只爲網絡的東西。所以你有一個這個特定大小的線程池。

前攝器模式可能對您有趣:

http://en.wikipedia.org/wiki/Proactor_pattern

如果你正在尋找一個可以處理這樣的事情一個圖書館,你可以看看即將到來的c + + Boost庫命名Boost.Asynchronous:

https://github.com/henry-ch/asynchronous

該庫仍處於開發階段,但真的很好。我已經用庫創建了一些簡單的客戶端/服務器應用程序。

+0

或者他可以使用現有的boost庫asio:http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio.html – Peter 2014-09-05 14:58:59

+0

當然,Boost.Asio目前可用。但Boost.Asio有一些令人討厭的錯誤。使用Boost.Asio編寫處理多個連接的服務器並不是一件有趣的事情;-) – Franz 2014-09-05 15:48:16