2013-11-25 40 views
1

我目前正在接受多個客戶端的服務器上工作。什麼時候用C++類鎖定互斥鎖

在服務器端我有一個線程池(手工製作,做工精細)午飯多線程:

ThreadPool::bind(new TCPReceiver()); 
ThreadPool::bind(new TCPSender()); 

一旦一個類被綁定到ThreadPool,其start()函數被調用。

所以basicaly什麼我的服務器做的是:

  • 線程綁定
  • 接受一個或多個客戶
  • 客戶的指針到TCPReceiver客戶端列表
    • TCPReceiver執行socket.receive(),並推動接收數據,以在客戶端的消息隊列
  • 附加客戶端的指針TCPSender客戶名單
    • TCPSender執行socket.send()和發送端的輸出消息隊列

因此,一旦一個客戶端連接,其類的指針被連接到2個線程,一個誰讀的插座,一個發送套接字。儘管如此,主線程(服務器)彈出客戶端的輸入消息隊列。

class Server { 
    std::list<Client*> clients; 

    TCPReceiver receive; 
    TCPSender send; 

    public: 
    void *start(); 
} 

class Client { 
    std::list<NetworkMessage*> inQueue; 
    IMutex *inMutex; 

    std::list<NetworkMessage*> outQueue; 
    IMutex *outMutex; 

    Socket *socket; 
} 

class TCPReceiver { 
    std::list<Client*> clients; 

    public: 
    void *start(); 
} 

class TCPSender { 
    std::list<Client*> clients; 

    public: 
    void *start(); 
} 

我的問題(s)爲:

從服務器/ TCPReceiver/TCPSender類,我可以訪問/使用客戶端指針沒有鎖定的客戶端類,但只能鎖定客戶端的消息隊列彈出/推在上面 ?

請問2個線程可以同時調用不同的客戶的會員功能?

我可以調用的std ::列表的成員不鎖定的std ::列表(見(*吧) - > inQueue.empty()調用)的功能呢?

void Server::start() { 
    for (std::list<Client*>::iterator it = this->clients.begin(); it != this->clients.end(); ++it) { 
    if (!(*it)->inQueue.empty()) { 
     (*it)->inMutex->lock(); 
     (*it)->inQueue.front(); 
     (*it)->inQueue.pop_front(); 
     (*it)->inMutex->unlock(); 
    } 
    } 
} 

同時對TCPReceiver:

void TCPReceiver::start() { 
    for (std::list<Client*>::iterator it = this->clients.begin(); it != this->clients.end(); ++it) { 
     std::string msg = (*it)->socket->receive(); 
     if (!msg.empty()){ 
      (*it)->inMutex->lock(); 
      (*it)->inQueue.push_back(msg); 
      (*it)->inMutex->unlock(); 
     } 
    } 
} 

(我知道插座應該有一個互斥量太多,但它不是我想要現在就understund)

+1

正如一個側面說明:您可能需要手動考慮基於RAII基於作用域的鎖,而不是鎖定和解鎖互斥 - 這樣你可以避免引起的異常(見的情況下不釋放互斥死鎖: lock_guard](http://en.cppreference.com/w/cpp/thread/lock_guard))。 – Hulk

+0

你說得對。今天早上我在尋找答案時瞭解到了這一點。我會盡快實施它,thx的提示。 – EoiFirst

+0

每個客戶端都有自己的消息列表,因此每個客戶端都有相應的互斥鎖。 – EoiFirst

回答

1

是,兩個線程可以確實同時執行相同實例的方法。您需要某種同步機制來防止由於同時修改相同值而導致競爭狀況。閱讀並不比在這方面寫作更危險,因爲正在進行寫操作時的閱讀可能會導致垃圾值被讀取。

基本上,這意味着你應該之前鎖定檢查隊列是否爲空,(因爲你的線程可能是線和下一個之間暫停),但你並不需要外界鎖定環路的迭代客戶端,只要保證客戶端列表在迭代過程中不發生變化。

你需要確保沒有線程訪問你的任何對象,而它處於無效狀態。對於像你所描述的生產者 - 消費者類型的情況,你可能有興趣瞭解condition variables,它提供了一種等待某些狀態改變的方法。 (例如等待空隊列不再爲空)。

注意,在這個例子中你提供,你只遍歷clients一次,並添加/ /到每個隊列中刪除最多一個消息。

+0

好的,所以我可以在不鎖定的情況下閱讀,只有當我讀取的數據不能寫入時,List迭代器纔是線程安全的。好消息。 (在我的代碼示例中,我沒有顯示條件變量/循環啓動/停止只是爲了讓我的解釋儘可能清晰)。 – EoiFirst