I`m writing a chat using WinSock2 and WinAPI functions. And I have a little trouble.
I store the std::vector of client connections on server. When new client connects, new thread starts and all work with the client is done in this new thread. I do not use classes (I know it is not very good) so this list of connections is just defined as global variable.
It seems to me that it can be a situation when several threads try to access this list simultaneously. Though I have not noticed that there are any problems with that, do I need to do something like this:
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); }
So, does my situation require using CRITICAL_SECTION and am I just the lucky guy who did not find a mistake?
Yes, you are just lucky never to experience any problems. This is the problem with synchronization issues and race conditions, that the code will work in 99.9% of all cases, and when disaster strikes you won’t know why.
I would take away the constructor taking a CRITICAL_SECTION as a parameter since it is not clear without looking at (presumably non-existing) documentation to realize that the constructor will initialize it.