2008-12-26 38 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使例外安全更容易 。 (当然,它需要 保持对 临界区的引用。)这个 使它更容易安全地 在面对异常时序列化你的其他成员 函数。