Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on 

What does std::atomic give me?

Ah hello.  

I have asked about std::atomic in a couple of questions before, and have had some falacies I was holding corrected.  Here is the code I have used in previous questions:

class CCounter
{
public:
	CCounter(int nVal = 0) : m_nVal(nVal) {}
	int operator++(int) { int nVal = m_nVal; ++m_nVal; return nVal; }
	int operator++() { m_nVal++; return m_nVal; }
	int m_nVal;
};

Open in new window


Can someone explain what benefit I get by using a std::atomic<CCCounter> as opposed to just a normal CCounter?  I can just use the appropriate atomic inrement functions in my operator++, so what does the atomic<> template give me exactly?  I have googled for this but all the information is about the built in specialisations, nothing for custom classes.

TIA
C++

Avatar of undefined
Last Comment
mrwad99
ASKER CERTIFIED SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> and the brilliant remarks made by rix
Thank you, Sara - that's very kind of you.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

I need to modify some of my previous comment...

So, it seems that only the intrinsic types provide the full spectrum of operators for specialisation (I've only just realise this -sorry).

http://en.cppreference.com/w/cpp/atomic/atomic

There are non-member function template equivalents for all member functions of std::atomic. Those non-member functions may be additionally overloaded for types that are not specializations of std::atomic, but are able to guarantee atomicity. The only such type in the standard library is std::shared_ptr<T>.
For an atomic type of T only assignment is available, which is achieve via in-place constructor (hence the need for the class to be trivially copy constructable). The std::atomic assignment operator makes sure this is an atomic operation, which it can do because the object (and hence all the members) are trivially copy constructable. So, in that respect, you need to nothing special for assignment; by default the std:atomic class with ensure that is always atomic.

For other operations you need to implement your own free-standing versions of member functions to support the framework. For example, consider a class foo that has an addition operator. This will not be available via the atomic version by default so you will need to implement your own.

Example:

#include <atomic>

class foo
{
public:
   foo(int x = 0) noexcept
      : x_(x)
   {
   }

   foo operator + (foo rhs) const
   {
      return rhs.x_ + rhs.x_;
   }

private:
   int x_;
};

template<typename T>
foo operator +(std::atomic<T> const & lhs, T const & rhs)
{
   return lhs.load() + rhs;
}

int main()
{
   auto && a = std::atomic<foo>(foo(1));
   auto && b = a + foo(2);
}

Open in new window


Here's another example:

#include <atomic>

class foo
{
public:
   foo(int x = 0) noexcept
      : x_(x)
   {
   }

   foo & operator += (foo rhs)
   {
      x_ += rhs.x_;
      return *this;
   }

private:
   int x_;
};

template<typename T>
std::atomic<T> operator +=(std::atomic<T> & lhs, T const & rhs)
{
   return lhs.load() += rhs;
}

int main()
{
   auto && a = std::atomic<foo>(foo(1));
   a += foo(2);
}

Open in new window


And yet another:

#include <atomic>

class foo
{
public:
   foo(int x = 0) noexcept
      : x_(x)
   {
   }

   foo operator ++()
   {
      return ++x_;
   }

private:
   int x_;
};

template<typename T>
std::atomic<T> & operator ++(std::atomic<T> & x)
{
   x.store(++x.load());
   return x;
}

int main()
{
   auto && a = std::atomic<foo>(foo(1));
   ++a;
}

Open in new window


I hope that makes sense, and I apologise if my previous comment was a little misleading. I didn't realise only the integral version of std::atomic<> (such as int, long, char and pointer types and so on) had the full spectrum of class member operators available for you to specialise. In the class T version you have to do it by implementing free standing functions. Not really sure why this is the case, since all the operators could be implemented given that assignment is always atomic!
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

This has turned out to be a really rather interesting question. Although I've been using std::atomic for quite a while now I never really bothered to give much thought to how it actually worked. Now I've done so I realise just how elegant it is as a solution. The fact it only supports POD types now makes perfect sense to me (again, I didn't really thing it through before - heh).

It means it can do a low-level bitwise copy of the objects in a mutually exclusive memory sync'd way without needing to know anything special about the class. So, in that respect all assignments are atomic. Everything else you'd want to do with an object can be supported via free-standing operators that you overload for your atomic type.
Avatar of mrwad99
mrwad99
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

Thanks again both :)
Avatar of mrwad99
mrwad99
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

Sara I just typed you first example and it won't compile due to the member std::atomic<int> making the class not trivially copyable, so I'd have to use InterlockedIncrement functions instead...
C++
C++

C++ is an intermediate-level general-purpose programming language, not to be confused with C or C#. It was developed as a set of extensions to the C programming language to improve type-safety and add support for automatic resource management, object-orientation, generic programming, and exception handling, among other features.

58K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo