6

I have this c++ code (VS 2008):

LONGLONG res = InterlockedIncrement64(&m_longlong);

running along it, I would like to be able to read from the same variable

LONGLONG res = InterlockedWHAT?64(&m_longlong)

Since this is a 64-bit variable, a simple read is not considered threadsafe, yet I cannot find the correct InterlockedXXX.

How should I read this variable?

Leo
  • 1,213
  • 2
  • 13
  • 26
  • on 64bit architecture, an aligned 64bit read (QWORD) ought to be atomic, IIRC. Look at tr1/boost/c++0x atomic for a 'non-stress' portable solution – sehe Oct 17 '11 at 13:08
  • thanks but I rather not link to a whole new library right now. lookin for InterlockedXXX solution – Leo Oct 17 '11 at 13:11
  • the idea of a comment is that is NOT an answer :) I was just supplying thoughts. If you know the arch, you might just make sure of the alignment and be done. The question is underconstrained which is why this is not an answer. – sehe Oct 17 '11 at 13:13
  • @sehe: You cannot just read an aligned `QWORD`. In order for concurrency to be safe you need two things, atomicity and write/read ordering. Even if the 64bit cpu will read the value atomicly the optimizer or CPU may mess with the read in unexpected ways. – deft_code Oct 17 '11 at 14:09

4 Answers4

7
LONGLONG res = InterlockedCompareExchange64(&m_longlong, 0, 0);
Henrik
  • 23,186
  • 6
  • 42
  • 92
  • @user991339 - another thread could modify the value while it's read for pushing on the stack as second parameter. The return value would be OK, but the shared variable would then contain garbage. – Henrik Oct 17 '11 at 13:10
  • 1
    `InterlockedExchange64` is no good. You would have to call it as `InterlockedExchange64(&val, val)` and now you should see the problem. How do you read the value of `val` to pass as the second parameter? That's the same problem you started with. – David Heffernan Oct 17 '11 at 13:12
  • @Henrik - this could happen with InterlockedCompareExchange as well, when m_longlong == 0 and 0 is pushed into the stack while another thread writes some other value, couldn't it? – Leo Oct 17 '11 at 13:13
  • No it could not. If `m_longlong == 0` then `m_longlong` will be set to 0 (i.e. no change), or otherwise `m_longlong` will not be modified. In other words the code in this answer cannot modify `m_longlong`. – David Heffernan Oct 17 '11 at 13:15
  • @David Heffernan - yes it would be set to 0 and that's the problem. while this 0 is being pushed into the stack, another thread writes "100" to m_longlong, then that 0 get written and overrides the "100". EDIT: Oops - then 100 != 0, my bad – Leo Oct 17 '11 at 13:17
  • @user No, this is an interlocked operation. It is atomic. No other interlocked operation can interfere with this atomic operation. – David Heffernan Oct 17 '11 at 13:19
  • 2
    You should pick a value that `m_longlong` is unlikely to have, to avoid dirtying the cache line. – Raymond Chen Oct 17 '11 at 13:43
3

You can use InterlockedOr64 and pass zero as the second parameter. So far as I can tell this does not have a requirement of Vista, presumably as it is implemented with compiler intrinsics.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    Note that this modifies the value (writes the result back, even though it is numerically identical), which can cause performance issues since it dirties the cache line. – Raymond Chen Oct 17 '11 at 13:44
  • @Raymond Thank you for adding that. What would be your preferred solution to the question? – David Heffernan Oct 17 '11 at 13:55
  • 2
    I would use `InterlockedCompareExchange` with an unlikely value. http://blogs.msdn.com/10152296.aspx – Raymond Chen Oct 17 '11 at 15:50
3
LONGLONG res = InterlockedOr64(&m_longlong, 0);

If your programm runs only on 64-Bit you can simply read the value. MSDN states that

Simple reads and writes to properly aligned 64-bit variables are atomic on 64-bit Windows.

don_jones
  • 842
  • 7
  • 13
0

With VS 2019 you should use __iso_volatile_load64, which is plain load, so it is more efficient than InterlockedCompareExchange64

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79