Andre said:
Yes, he was talking about using your wrapper class. It was simply not
shown in the code example for brevity's sake. So to rephrase:
while (!vec.empty())
vec.pop_back();
Replace "vec." with "obj->GetLockedObject()->". So let's assume we start
with a 1000000 element vector, and we launch 100 threads with the above
code in it to clear out the vector (and for some strange reason we don't
want to just .clear() it...).
Let's continue the example that say we're down to the last element, and
25 of the threads check vec.empty() and then there's a thread context
switch right after that. The other 75 threads may be just after the
vec.pop_back(). One of the 75 gets the thread context, checks for
vec.empty() and then performs the vec.pop_back(), then context switch.
Say the remaining 74 threads are the ones that get the next contexts.
They all test vec.empty(), find the vector empty, and proceed along their
codepath. Finally those first 25 that were sitting just after the
vec.empty() call get their timeslices. All 25 will attempt a pop_back on
an empty vector. Boom. (OK, Undefined Behaviour)
Translation, your wrapper class does _not_ provide thread safety as a
silver bullet. It _only_ provides thread safety in a single atomic
operation. As soon as you need multiple operations on the object to
perform a task, you're implementation risks a context switch between the
two operations where the state of the object may be modified.
That's incorrect. If you have a better understanding of the wrapper
class, you'll see that you can do the above logic in a thread safe
manner with the wrapper class protecting the object from being access
simultaneously by multiple threads.
If you have to perform several functions who's results depend on each
other, then you can lock access to the object by using a RefLock
variable.
For the duration of the RefLock variable, the object is locked and only
the one thread can access it.
You can then safely do multiple functions who's results depend on each
other, and do it in a thread safe way.
example:
ThreadSafeObject<std::vector<int> >::RefLock MyLockedVec =
MyRefThreadSafeOjbectTestCase.MyThreadSafeVectorInstance.GetLockedObject();
if (MyLockedVec->size() > 10000 && MyLockedVec->size()&1) //Due odd
numbers
{
MyLockedVec->pop_back();
For a more complex example see following Unit Test class that is able
to perform all above senerios in an thread safe way.
http://code.axter.com/ThreadSafeOjbectTestCase.h
http://code.axter.com/ThreadSafeOjbectTestCase.cpp
The above unit test has 13 threads accessing the same object, and using
the ThreadSafeObject class to allow the objects to be access in a
thread safe manner.
This OO approach is safer, and it makes application locks redundant.