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;
}
};
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;
}
};
To copy to clipboard, switch view to plain text mode
And std::vector in a data structure:
struct ThreadInput
{
std::vector<AtomicUInt64> *atomsUsed = NULL;
//other variables
};
struct ThreadInput
{
std::vector<AtomicUInt64> *atomsUsed = NULL;
//other variables
};
To copy to clipboard, switch view to plain text mode
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();
}
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();
}
To copy to clipboard, switch view to plain text mode
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
);
}
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);
}
To copy to clipboard, switch view to plain text mode
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?
Bookmarks