7

I want to use InterlockedExchange from the WinAPI to use a lock free synchronization of threads.
At the moment I have a class like this.

struct DataExchange
{
    volatile LONG m_value;
    void SetValue(LONG newVal)
    {
        InterlockedExchange(&m_value, newVal);
    }

    LONG GetValue()
    {
        LONG workVal=0;
        InterlockedExchange(&workVal, m_value);
        return workVal;
    }
};

One thread can set a new value and an other thread can read this value.
Now what I want to do is to change the LONG value to be a struct. Is there any way in the WinAPI how I can copy a struct lock free?

mkaes
  • 13,781
  • 10
  • 52
  • 72
  • Using atomic access on the variable doesn't actually make it lock-free, because atomic access is also a very small critical section, albeit implemented at the CPU. – sep May 24 '11 at 11:46
  • 1
    If you want lock-free, fence-free maybe you should consider this URL: http://calvados.di.unipi.it/dokuwiki/doku.php?id=ffnamespace:about – sep May 24 '11 at 11:50
  • Lockfree is really wrong in this context. But it is the fastest synchronization I can use on a windows machine. @sep +1 for the nice link. I will have a look at as soon I have some time – mkaes May 24 '11 at 11:59
  • 2
    Raymond Chen ([The Old New Thing](http://blogs.msdn.com/b/oldnewthing/)) wrote quite a bit on this topic last month, e.g. [Lock-free algorithms: The one-time initialization](http://blogs.msdn.com/b/oldnewthing/archive/2011/04/07/10150728.aspx) – MSalters May 24 '11 at 12:19
  • Not if the `struct` is larger than 32 bits. But what you can do is exchange a *pointer* to a `struct`. – David May 25 '11 at 00:51
  • Note also that your `GetValue` implementation corrupts the value... – Raymond Chen Oct 08 '11 at 20:26

4 Answers4

3

No there isn't unless you can fit your struct into 32 bits, in which case you can continue to use InterlockedExchange.

2

You can get an atomic operation on a 64-bit value using InterlockedExchange64 on 64-bit platforms and Windows Vista/7. That would be enough to fit two 32-bit int values in a struct.

Since the function is implemented with a complier instrinsic, it's basically calling a platform-dependent assembly instruction like CMPXCHG on x86. Since that instruction only works at a maximum (on 64-bit platforms) on a 64-bit register source operand, a 64-bit register or memory destination operand, and the RAX register, there is only a certain-size value you can perform an atomic operation on using single assembly instructions without incorporating some type of lock or semaphore to create a critical section.

Jason
  • 31,834
  • 7
  • 59
  • 78
1

Only if the struct is exactly 32 bits.

An alternative is to use an InterlockedExchange on a pointer to a struct. The struct has to be immutable (or never change it). To update the struct, make a new one and then exchange the pointer. You have to be careful about destroying the struct to make sure it is only done once, and only if no one is using it.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • 1
    @lou-franco: But using new and delete would be contrary to my goal to be as fast as possible in this case. Because the heap manager will also do some internal locking. – mkaes May 24 '11 at 12:10
  • 1
    @mkaes: Have you measured? Don't ignore a potential method because it might exhibit certain behaviour - you should check. (I also suggested using a pointer in a comment to your question, and I think it's worth investigating for you.) – David May 27 '11 at 01:15
1

The best you can do is to use InitializeCriticalSectionAndSpinCount function which will not wait for the lock if it is possible to take an ownership fast enough.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212