Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Atomic operations involving __int64 on 32 bit machines

Atomic operations involving __int64 on 32 bit machines

Scheduled Pinned Locked Moved C / C++ / MFC
questionperformancetutorial
4 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    Eikthrynir
    wrote on last edited by
    #1

    Hello! Let's say we have the following:

    class MyClass
    {
    public:
    void SetValue( __int64 a_i64Value );
    __int64 GetValue( void ) const;

    private:
    __int64 m_i64Value;
    };

    void MyClass::SetValue( __int64 a_i64Value )
    {
    m_i64Value = a_i64Value;
    }

    __int64 MyClass::GetValue( void ) const
    {
    return m_i64Value;
    }

    We also have two threads: ThreadA and ThreadB, each setting the value of m_i64Value to something different. Let's assume that ThreadA executes and SetValue is called. It writes 32 bits of m_i64Value, ThreadB executes, it calls SetValue which also writes 32 bits of m_i64Value, then ThreadA resumes and continues writing the other 32 bits of m_i64Value. Finally, ThreadB also writes the other half of m_i64Value. Eventually, m_i64Value contains garbage, invalid data. Question 1: Is this scenario valid? Can it happen on a 32 bit machine? Anyway, this can be solved using InterlockedExchange64, right? But let's suppose there is a ThreadC which needs to read that value, using the member function GetValue. When returning from GetValue, 32 bits of m_i64Value get written to EAX register and 32 bits to EDX. Question 2: What if 32 bits get written to EAX, ThreadB resumes and writes to m_i64Value and after that, ThreadC resumes and the other 32 bits (changed by ThreadB) go to EDX? Is this also a possibility on 32 bit machines? If yes, what is the best way to return such a value (__int64, in this example)? I guess one of the solutions could be this one:

    void GetValue( __int64 *a_pi64Value )
    {
    if ( NULL != a_pi64Value )
    {
    InterlockedExchange64( *a_pi64Value, m_i64Value );
    }
    }

    Question 3: But what if we still want to actually return the value and not copy it to the memory pointed by a_pi64Value? Can this be done somehow thread-safely and using the return instruction? Thanks in advance!

    L 1 Reply Last reply
    0
    • E Eikthrynir

      Hello! Let's say we have the following:

      class MyClass
      {
      public:
      void SetValue( __int64 a_i64Value );
      __int64 GetValue( void ) const;

      private:
      __int64 m_i64Value;
      };

      void MyClass::SetValue( __int64 a_i64Value )
      {
      m_i64Value = a_i64Value;
      }

      __int64 MyClass::GetValue( void ) const
      {
      return m_i64Value;
      }

      We also have two threads: ThreadA and ThreadB, each setting the value of m_i64Value to something different. Let's assume that ThreadA executes and SetValue is called. It writes 32 bits of m_i64Value, ThreadB executes, it calls SetValue which also writes 32 bits of m_i64Value, then ThreadA resumes and continues writing the other 32 bits of m_i64Value. Finally, ThreadB also writes the other half of m_i64Value. Eventually, m_i64Value contains garbage, invalid data. Question 1: Is this scenario valid? Can it happen on a 32 bit machine? Anyway, this can be solved using InterlockedExchange64, right? But let's suppose there is a ThreadC which needs to read that value, using the member function GetValue. When returning from GetValue, 32 bits of m_i64Value get written to EAX register and 32 bits to EDX. Question 2: What if 32 bits get written to EAX, ThreadB resumes and writes to m_i64Value and after that, ThreadC resumes and the other 32 bits (changed by ThreadB) go to EDX? Is this also a possibility on 32 bit machines? If yes, what is the best way to return such a value (__int64, in this example)? I guess one of the solutions could be this one:

      void GetValue( __int64 *a_pi64Value )
      {
      if ( NULL != a_pi64Value )
      {
      InterlockedExchange64( *a_pi64Value, m_i64Value );
      }
      }

      Question 3: But what if we still want to actually return the value and not copy it to the memory pointed by a_pi64Value? Can this be done somehow thread-safely and using the return instruction? Thanks in advance!

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      Eikthrynir wrote:

      Question 1: Is this scenario valid? Can it happen on a 32 bit machine?

      Yes as the MSDN states in the article Interlocked Variable Access[^]: Reads and writes to 64-bit values are not guaranteed to be atomic on 32-bit Windows. Reads and writes to variables of other sizes are not guaranteed to be atomic on any platform.

      Eikthrynir wrote:

      Question 2: What if 32 bits get written to EAX, ThreadB resumes and writes to m_i64Value and after that, ThreadC resumes and the other 32 bits (changed by ThreadB) go to EDX? Is this also a possibility on 32 bit machines? If yes, what is the best way to return such a value (__int64, in this example)?

      Eikthrynir wrote:

      Question 3: But what if we still want to actually return the value and not copy it to the memory pointed by a_pi64Value? Can this be done somehow thread-safely and using the return instruction?

      I would personally do it like this://Add zero to the value and return the initial value. LONGLONG GetValue(__int64 *a_pi64Value) { return InterlockedExchangeAdd64(a_pi64Value,0); }
      Best Wishes, -David Delaune

      modified on Wednesday, May 13, 2009 11:41 AM

      E 1 Reply Last reply
      0
      • L Lost User

        Eikthrynir wrote:

        Question 1: Is this scenario valid? Can it happen on a 32 bit machine?

        Yes as the MSDN states in the article Interlocked Variable Access[^]: Reads and writes to 64-bit values are not guaranteed to be atomic on 32-bit Windows. Reads and writes to variables of other sizes are not guaranteed to be atomic on any platform.

        Eikthrynir wrote:

        Question 2: What if 32 bits get written to EAX, ThreadB resumes and writes to m_i64Value and after that, ThreadC resumes and the other 32 bits (changed by ThreadB) go to EDX? Is this also a possibility on 32 bit machines? If yes, what is the best way to return such a value (__int64, in this example)?

        Eikthrynir wrote:

        Question 3: But what if we still want to actually return the value and not copy it to the memory pointed by a_pi64Value? Can this be done somehow thread-safely and using the return instruction?

        I would personally do it like this://Add zero to the value and return the initial value. LONGLONG GetValue(__int64 *a_pi64Value) { return InterlockedExchangeAdd64(a_pi64Value,0); }
        Best Wishes, -David Delaune

        modified on Wednesday, May 13, 2009 11:41 AM

        E Offline
        E Offline
        Eikthrynir
        wrote on last edited by
        #3

        Hello! Thanks for the reply! I would like to make a few comments regarding your version of GetValue... 1. You call InterlockedExchange64 with a_pi64Value as the first parameter, so the __int64 variable pointed by a_pi64Value gets 0. Then, you return the previous value of that __int64 variable which is certainly not the one we are interested in, m_i64Value. 2. GetValue returns a LONGLONG value, so we find ourselves in exactly the same situation from Question 2 (concerning the EAX and EDX registers)... Best regards!

        L 1 Reply Last reply
        0
        • E Eikthrynir

          Hello! Thanks for the reply! I would like to make a few comments regarding your version of GetValue... 1. You call InterlockedExchange64 with a_pi64Value as the first parameter, so the __int64 variable pointed by a_pi64Value gets 0. Then, you return the previous value of that __int64 variable which is certainly not the one we are interested in, m_i64Value. 2. GetValue returns a LONGLONG value, so we find ourselves in exactly the same situation from Question 2 (concerning the EAX and EDX registers)... Best regards!

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #4

          Eikthrynir wrote:

          1. You call InterlockedExchange64 with a_pi64Value as the first parameter, so the __int64 variable pointed by a_pi64Value gets 0. Then, you return the previous value of that __int64 variable which is certainly not the one we are interested in, m_i64Value.

          If the 64 bit integer variable you want to read atomically is m_i64Value Then the correct way to atomically read the value is:__int64 i64Val = InterlockedExchangeAdd64(m_i64Value,0);

          Eikthrynir wrote:

          2. GetValue returns a LONGLONG value, so we find ourselves in exactly the same situation from Question 2 (concerning the EAX and EDX registers)...

          This statement does not make any sense to me. Best Wishes, -David Delaune

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups