Safety interlocking grille

I have a C ++ library that needs to do some calculations on multiple threads. I created independent code for the threads (i.e. there are no common variables between them), with the exception of one array. The problem is that I do not know how to make it thread safe.

I looked at locking / unlocking mutex ( QMutex , since I use Qt), but it is not suitable for my task - while one thread blocks the mutex, other threads will wait!

Then I read about std::atomic , which looked exactly as I needed. However, I tried using it as follows:

 std::vector<std::atomic<uint64_t>> *myVector; 

And he produced a compiler error (using the remote function 'std :: atomic :: atomic (const std :: atomic &)'). Then I found a solution - use a special shell for std::atomic . I tried this:

 struct AtomicUInt64 { std::atomic<uint64_t> atomic; AtomicUInt64() : atomic() {} AtomicUInt64 ( std::atomic<uint64_t> a ) : atomic ( atomic.load() ) {} AtomicUInt64 ( AtomicUInt64 &auint64 ) : atomic ( auint64.atomic.load() ) {} AtomicUInt64 &operator= ( AtomicUInt64 &auint64 ) { atomic.store ( auint64.atomic.load() ); } }; std::vector<AtomicUInt64> *myVector; 

This thing compiles successfully, but when I cannot fill the vector:

 myVector = new std::vector<AtomicUInt64>(); for ( int x = 0; x < 100; ++x ) { /* This approach produces compiler error: * use of deleted function 'std::atomic<long long unsigned int>::atomic(const std::atomic<long long unsigned int>&)' */ AtomicUInt64 value( std::atomic<uint64_t>( 0 ) ) ; myVector->push_back ( value ); /* And this one produces the same error: */ std::atomic<uint64_t> value1 ( 0 ); myVector->push_back ( value1 ); } 

What am I doing wrong? I guess I tried everything (maybe not, one way or another) and nothing helped. Are there any other ways for threaded access to an array in C ++?

By the way, I am using the MinGW 32bit 4.7 compiler on Windows.

+6
source share
3 answers

Here is a cleaned version of your AtomicUInt64 type:

 template<typename T> struct MobileAtomic { std::atomic<T> atomic; MobileAtomic() : atomic(T()) {} explicit MobileAtomic ( T const& v ) : atomic ( v ) {} explicit MobileAtomic ( std::atomic<T> const& a ) : atomic ( a.load() ) {} MobileAtomic ( MobileAtomic const&other ) : atomic( other.atomic.load() ) {} MobileAtomic& operator=( MobileAtomic const &other ) { atomic.store( other.atomic.load() ); return *this; } }; typedef MobileAtomic<uint64_t> AtomicUInt64; 

and use:

 AtomicUInt64 value; myVector->push_back ( value ); 

or

 AtomicUInt64 value(x); myVector->push_back ( value ); 

Your problem was that you took the value of std::atomic by value, which leads to blocking the copy. Oh, and you failed to return with operator= . I also made some constructors explicit, probably useless. And I added const to your copy constructor.

I would also want to add store and load methods to MobileAtomic , which go into atomic.store and atomic.load .

+5
source

You are trying to copy a non-copied type: the AtomicUInt64 constructor takes an atomic value by value.

If you need it to be initialized from atomic , then it should take an argument by reference (const). However, in your case, this is not like what you need to initialize from atomic in general; why not initialize instead of uint64_t ?

Also a few minor points:

  • The copy constructor and assignment operator must take their values ​​using the const reference to allow temporary copies to be copied.

  • Highlighting a vector with new is a rather strange thing; you just add an extra level of indirection without any benefits.

  • Make sure you never resize the array while other threads can access it.

+1
source

This line

 AtomicUInt64 ( std::atomic<uint64_t> a ) : atomic ( atomic.load() ) {} 

You completely ignore the argument you pass. You probably want it to be a.load (), and you probably want to take the elements from the const link so that they are not copied.

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

As for what you are doing, I'm not sure if this is correct. Modification of variables inside the array will be atomic, but if the vector is changed or redistributed (which is possible using push_back ), then there is nothing to guarantee that your modifications to the array will work between threads and be atomic.

+1
source

Source: https://habr.com/ru/post/946507/


All Articles