2008-12-26 35 views
2

我正在用WinSock2和WinAPI函數寫一個聊天。我有一點麻煩。
我將客戶端連接的std :: vector存儲在服務器上。當新客戶端連接時,新線程啓動,並且所有與客戶端一起工作都在這個新線程中完成。我不使用類(我知道它不是很好),所以這個連接列表被定義爲全局變量。
在我看來,它可能是多個線程同時嘗試訪問此列表的情況。雖然我還沒有注意到,有與任何問題,我需要做這樣的事情:關鍵部分 - 是或不是?


template 
class SharedVector { 
    std::vector vect; 
    CRITICAL_SECTION cs; 
    SharedVector(const SharedVector& rhs) {} 
public: 
    SharedVector(); 
    explicit SharedVector(const CRITICAL_SECTION& CS); 
    void PushBack(const T& value); 
    void PopBack(); 
    unsigned int size(); 
    T& operator[](int index); 
    virtual ~SharedVector(); 
}; 

template 
SharedVector::SharedVector() { 
    InitializeCriticalSection(&cs); 
} 

template 
SharedVector::SharedVector(const CRITICAL_SECTION& r): cs(r) { 
    InitializeCriticalSection(&cs); 
} 

template 
void SharedVector::PushBack(const T& value) { 
    EnterCriticalSection(&cs); 
    vect.push_back(value); 
    LeaveCriticalSection(&cs); 
} 

template 
void SharedVector::PopBack() { 
    EnterCriticalSection(&cs); 
    vect.pop_back(); 
    LeaveCriticalSection(&cs); 
} 

因此,沒有使用CRITICAL_SECTION我的情況需要和我只是幸運的人誰沒有找到一個錯誤?

回答

7

是的,你是幸運的,永遠不會遇到任何問題。這是同步問題和競爭條件的問題,代碼將在99.9%的情況下起作用,並且當災難發生時您將不知道爲什麼。

我將帶走構造函數以CRITICAL_SECTION作爲參數,因爲如果不查看(大概不存在的)文檔來實現構造函數將對其進行初始化,則不清楚。

1

是的,如果你公開一個像這樣的全局向量,你肯定需要鎖定它的任何讀/寫。是的,這可能會嚴重損害你的表現。

此外,每個請求一個新的線程通常也不是一個好主意。你爲什麼不重新設計你的應用程序來使用IO完成端口呢?

0

順便說一下,將這個向量聲明爲全局變量並不是一個好方法。將它製作成本地產品會更好嗎?

3

此代碼不是異常安全的,vector push_back和pop_back方法可能會引發異常,並且您在此處可能存在死鎖。 這種方法:

unsigned int size(); 
T& operator[](int index); 

也必須被同步,因爲他們訪問的數據,可以由另一個線程修改。例如,你可以這樣訪問數據:

value = shared_vector[shared_vector.size() - 1]; 

,並在同一時間,另一個線程可以這樣做:

shared_vector.PopBack(); 
3

我對你的最大的問題是建築。每個連接的線程是否真的需要直接訪問此數組的其他連接?他們不應該真的排隊抽象的消息嗎?如果每個連接線程都意識到它所在的宇宙的實現細節,我希望你會在某個地方遇到麻煩。

但是讓我們假設連接螺紋真的需要彼此直接進入...

全局變量並不總是有害的;學校只是教它,因爲它比提供細緻入微的理解更容易。你必須知道一個全局變量的確切含義,假設一個全局是錯誤的選擇,直到你發現你別無選擇,這是一個體面的經驗法則。它解決了一些問題,其中之一就是編寫一個函數:

SharedVector & GetSharedVector (void) 
{ 
    static SharedVector sharedVector; 
    return sharedVector; 
} 

這買你上課的時候被實例化提供更多的控制比你有一個全局變量,它可以是至關重要的,如果你有具有構造函數的全局變量之間的依賴關係,特別是如果這些全局變量產生了線程。它還讓你有機會介入某人想要訪問這個「全局」變量,而不是在直接捅到它時無能爲力地受到影響。

還有許多其他的想法值得思考。在沒有特定的順序...

  • 你很可能早已知道你在這裏使用的 模板語法 怪異;我假設你只是輸入了 這段代碼而沒有編譯它。
  • 你需要一個什麼都不做賦值運算符 在您的私人部分 防止事故(你有一個什麼都不做同樣的 理由複製 構造有)。
  • 顯式拷貝構造函數是 以多種方式分解。它需要 明確地複製向量或 你最終將在你的新的SharedVector實例中得到一個空向量。 它應該簡單地初始化它的 自己的關鍵部分而不是 複製它(然後初始化它)。 真的爲你的情況下,它可能 沒有任何意義,因爲網絡 連接沒有合理的 複製語義。
  • 您可以通過創建一個類 EnteredCriticalSection其 構造函數調用 EnterCriticalSection的,其 析構函數調用 LeaveCriticalSection使例外安全更容易 。 (當然,它需要 保持對 臨界區的引用。)這個 使它更容易安全地 在面對異常時序列化你的其他成員 函數。