PDA

View Full Version : Sharing a variable of type std::vector between QThread classes



ahawkthomas
5th June 2013, 04:31
Hello! I have a C++ library based on Qt 5 that uses multiple threads (classes inherited from QThread) for some computations. I need to share a STL vector between them (threads don't perform any pushing/popping with this vector, but they change it's values). I use the special wrapper around std::atomic:



struct AtomicUInt64
{
std::atomic<uint64_t> atomic;

AtomicUInt64() : atomic ( uint64_t() ) {}

explicit AtomicUInt64 ( uint64_t const &v ) : atomic ( v ) {}
explicit AtomicUInt64 ( std::atomic<uint64_t> const &a ) : atomic ( a.load() ) {}

AtomicUInt64 ( AtomicUInt64 const &other ) : atomic ( other.atomic.load() ) {}

AtomicUInt64 &operator= ( AtomicUInt64 const &other )
{
atomic.store ( other.atomic.load() );
return *this;
}

AtomicUInt64 operator++ ()
{
this->atomic++;
return *this;
}
};


And std::vector in a data structure:



struct ThreadInput
{
std::vector<AtomicUInt64> *atomsUsed = NULL;
//other variables
};


I initialize this structure in a class that manages threads:



CalculationThread threadData;
threadData.myVect = new std::vector<AtomicUInt64>();
for ( int x = 0; x < 100; ++x )
{
AtomicUInt64 value ( 0 );
threadData.myVect->push_back ( value );
}
//assign other variables in 'threadData'
for ( int x = 0; x < 2; ++x )
{
MyThread *thread = new MyThread ( threadData );
thread->start();
}


Finally, this is MyThread's 'void run()' impementation:



void MyThread::run()
{
uint64_t ull;
for ( ull = 0; ull < this->threadData.iterations; ++ull)
{
//increment the 100th value of 'myVect'
++this->threadInput.myVect->data()[99];
}
qDebug() << "Finished = " + QString::number(this->thredData.myVect->data()[99].atomic) + " | it = " + QString::number(ull);
}


So, when I set 'threadData.iterations' variable to ~490000 (this value is different for different threads), I get the following in Application Output:

"Finished = 491760 | it = 249654"
"Finished = 499308 | it = 499308"

And this is not what I expected to see. Why the first finished thread outputs that the 100th value of vector is 249654? Shouldn't it be more than iteration count, as there were 2 threads?
Maybe there are another ways to share a STL vector between instances of `MyThread` class inherited from QThread and assume that it is atomic?

pkj
5th June 2013, 06:15
Maybe there are another ways to share a STL vector between instances of `MyThread` class inherited from QThread and assume that it is atomic?
No there is no special way to share a std::vector or any c++ class for that matter.

And this is not what I expected to see. Why the first finished thread outputs that the 100th value of vector is 249654? Shouldn't it be more than iteration count, as there were 2 threads?
if your data, myVect is shared between the 2 threads you have created, I don't know why the result is alarming? Or is myVect/thread. How is it sharing then. Your datastructures are not clear, at least, to me.
Moreover, it is generally not required to sub-class QThread. QThread derived class stays in the thread you have created. Objects created in the run() have their affinity to the new thread. Since this is a tricky point missed by most, this is what the documentation has to say about subclassing QThread...qthread.html#subclassing-qthread

ahawkthomas
5th June 2013, 07:15
Or is myVect/thread. How is it sharing then. Your datastructures are not clear, at least, to me.

Sorry if I was not clear. I send the same pointer to std::vector object to threads. So they should use the same object in memory - and this object is std::vector. Threads increment the same value in this vector by one in the loop. When the loop ends on the last running thread, I expect to see in Application Output the value equals to (loop iterations * threads count), but I see another numbers.