Does anyone have a 64 bit atomic increment decrement?
- RichAlgeni
- Addict
- Posts: 914
- Joined: Wed Sep 22, 2010 1:50 am
- Location: Bradenton, FL
Does anyone have a 64 bit atomic increment decrement?
For integers in Windows?
The intrinsic does not seem to work. The SDK kernel32.lib does not seem to export the function, and I cannot find it in kernel32.dll.
There is some assembler listed in other posts, but it does not appear to work.
The intrinsic does not seem to work. The SDK kernel32.lib does not seem to export the function, and I cannot find it in kernel32.dll.
There is some assembler listed in other posts, but it does not appear to work.
Re: Does anyone have a 64 bit atomic increment decrement?
Code: Select all
Procedure.q AtomicIncrement64(*Var64)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Var64]
!mov rax, 1
!lock xadd [rdx], rax
!add rax, 1
CompilerElse
; store non-volatile registers
!mov [esp - 4], ebx
!mov [esp - 8], edi
; load 64 bit value into edx:eax
!mov edi, [p.p_Var64]
!mov eax, [edi]
!mov edx, [edi + 4]
; 64 bit atomic increment
!.l:
!mov ebx, 1
!mov ecx, 0
!add ebx, eax
!adc ecx, edx
!lock cmpxchg8b [edi]
!jnz .l
!mov eax, ebx
!mov edx, ecx
; restore non-volatile registers
!mov edi, [esp - 8]
!mov ebx, [esp - 4]
CompilerEndIf
ProcedureReturn
EndProcedure
Procedure.q AtomicDecrement64(*Var64)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Var64]
!mov rax, -1
!lock xadd [rdx], rax
!add rax, -1
CompilerElse
; store non-volatile registers
!mov [esp - 4], ebx
!mov [esp - 8], edi
; load 64 bit value into edx:eax
!mov edi, [p.p_Var64]
!mov eax, [edi]
!mov edx, [edi + 4]
; 64 bit atomic decrement
!.l:
!mov ebx, -1
!mov ecx, -1
!add ebx, eax
!adc ecx, edx
!lock cmpxchg8b [edi]
!jnz .l
!mov eax, ebx
!mov edx, ecx
; restore non-volatile registers
!mov edi, [esp - 8]
!mov ebx, [esp - 4]
CompilerEndIf
ProcedureReturn
EndProcedure
A.q = 5
For i = 1 To 10
Debug AtomicIncrement64(@A)
Next
Code: Select all
Procedure.q AtomicAdd64(*Var64, Value64.q)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Var64]
!mov rax, [p.v_Value64]
!lock xadd [rdx], rax
!add rax, [p.v_Value64]
CompilerElse
; store non-volatile registers
!mov [esp - 4], ebx
!mov [esp - 8], edi
; load 64 bit value into edx:eax
!mov edi, [p.p_Var64]
!mov eax, [edi]
!mov edx, [edi + 4]
; 64 bit atomic add
!.l:
!mov ebx, [p.v_Value64]
!mov ecx, [p.v_Value64 + 4]
!add ebx, eax
!adc ecx, edx
!lock cmpxchg8b [edi]
!jnz .l
!mov eax, ebx
!mov edx, ecx
; restore non-volatile registers
!mov edi, [esp - 8]
!mov ebx, [esp - 4]
CompilerEndIf
ProcedureReturn
EndProcedure
A.q = 5
For i = 1 To 10
Debug AtomicAdd64(@A, -1)
Next
For i = 1 To 6
Debug AtomicAdd64(@A, 1)
Next
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
- RichAlgeni
- Addict
- Posts: 914
- Joined: Wed Sep 22, 2010 1:50 am
- Location: Bradenton, FL
Re: Does anyone have a 64 bit atomic increment decrement?
Always appreciate your assistance Wilbert!
You're work is most instructive and helpful!
You're work is most instructive and helpful!
- RichAlgeni
- Addict
- Posts: 914
- Joined: Wed Sep 22, 2010 1:50 am
- Location: Bradenton, FL
Re: Does anyone have a 64 bit atomic increment decrement?
I'm sorry I have to ask this, but...
Could you write an Assembler process to force the variable (quad integer pointer) back to 0?
I am getting error C0000264, STATUS_RESOURCE_NOT_OWNED arbitrarily in this code:
Which seems impossible as the pointer used in the lock is not accessed in any other part of the program.
My thought is that I could use it as my own lock process.
Could you write an Assembler process to force the variable (quad integer pointer) back to 0?
I am getting error C0000264, STATUS_RESOURCE_NOT_OWNED arbitrarily in this code:
Code: Select all
While Not TryAcquireSRWLockExclusive(*updateLock)
Delay(20)
Wend
AddElement(updateMessageLog())
updateMessageLog()\messageLogKey = *messageData\messageKey
updateMessageLog()\messageLogTyp = #snpp
updateMessageLog()\messageResult = result
ReleaseSRWLockExclusive(*updateLock)
My thought is that I could use it as my own lock process.
Re: Does anyone have a 64 bit atomic increment decrement?
I'm not exactly sure if I understand what you want.RichAlgeni wrote:Could you write an Assembler process to force the variable (quad integer pointer) back to 0?
![Confused :?](./images/smilies/icon_confused.gif)
Do you want a procedure to set the value like the code below or do you need something else ?
Code: Select all
Procedure.q AtomicSetValue64(*Var64, Value64.q)
; the return value is the old value of *Var64
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Var64]
!mov rax, [p.v_Value64]
!lock xchg [rdx], rax
CompilerElse
; store non-volatile registers
!mov [esp - 4], ebx
!mov [esp - 8], edi
; load current value into edx:eax
!mov edi, [p.p_Var64]
!mov eax, [edi]
!mov edx, [edi + 4]
; 64 bit atomic exchange
!.l:
!mov ebx, [p.v_Value64]
!mov ecx, [p.v_Value64 + 4]
!lock cmpxchg8b [edi]
!jnz .l
; restore non-volatile registers
!mov edi, [esp - 8]
!mov ebx, [esp - 4]
CompilerEndIf
ProcedureReturn
EndProcedure
Procedure.q AtomicAdd64(*Var64, Value64.q)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Var64]
!mov rax, [p.v_Value64]
!lock xadd [rdx], rax
!add rax, [p.v_Value64]
CompilerElse
; store non-volatile registers
!mov [esp - 4], ebx
!mov [esp - 8], edi
; load current value into edx:eax
!mov edi, [p.p_Var64]
!mov eax, [edi]
!mov edx, [edi + 4]
; 64 bit atomic add
!.l:
!mov ebx, [p.v_Value64]
!mov ecx, [p.v_Value64 + 4]
!add ebx, eax
!adc ecx, edx
!lock cmpxchg8b [edi]
!jnz .l
!mov eax, ebx
!mov edx, ecx
; restore non-volatile registers
!mov edi, [esp - 8]
!mov ebx, [esp - 4]
CompilerEndIf
ProcedureReturn
EndProcedure
A.q = 5
For i = 1 To 10
Debug AtomicAdd64(@A, 1)
Next
AtomicSetValue64(@A, 0)
For i = 1 To 10
Debug AtomicAdd64(@A, -1)
Next
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
- RichAlgeni
- Addict
- Posts: 914
- Joined: Wed Sep 22, 2010 1:50 am
- Location: Bradenton, FL
Re: Does anyone have a 64 bit atomic increment decrement?
Let me explain my thought process, and see if it makes sense to you.
1. The initial value of the Global integer will be 0.
2. Threads created will use AtomicIncrement64() to increment the value, when work is required.
3. Only when the integer returned to a thread is 1 will the thread be considered to be granted access to a locked resource.
4. Any other value returned (2, 3, etc.) and the thread will wait a period of time, then proceed to step 2.
5. The thread that does the work will use AtomicSetValue64() to set the value of the integer back to 0 when the work is complete, indicating that the resource is unlocked and available to another thread to process work needed on the resource.
6. The thread that did the work will proceed to step 2.
1. The initial value of the Global integer will be 0.
2. Threads created will use AtomicIncrement64() to increment the value, when work is required.
3. Only when the integer returned to a thread is 1 will the thread be considered to be granted access to a locked resource.
4. Any other value returned (2, 3, etc.) and the thread will wait a period of time, then proceed to step 2.
5. The thread that does the work will use AtomicSetValue64() to set the value of the integer back to 0 when the work is complete, indicating that the resource is unlocked and available to another thread to process work needed on the resource.
6. The thread that did the work will proceed to step 2.
Re: Does anyone have a 64 bit atomic increment decrement?
Sounds logical
You could also consider a toggle bit; not sure what would work best.
AtomicBitSet sets bit 0 of the Flags value always to 1.
If it previously was 0, you can proceed. If not, you can consider it locked.
At the end of the procedure you can reset the bit to indicate it is no longer locked.
![Smile :)](./images/smilies/icon_smile.gif)
You could also consider a toggle bit; not sure what would work best.
Code: Select all
Procedure AtomicBitSet(*Mem, BitIdx.a = 0)
; the return value is the old bit value
!movzx eax, byte [p.v_BitIdx]
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Mem]
!lock bts [rdx], eax
CompilerElse
!mov edx, [p.p_Mem]
!lock bts [edx], eax
CompilerEndIf
!setc al
ProcedureReturn
EndProcedure
Procedure AtomicBitReset(*Mem, BitIdx.a = 0)
; the return value is the old bit value
!movzx eax, byte [p.v_BitIdx]
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Mem]
!lock btr [rdx], eax
CompilerElse
!mov edx, [p.p_Mem]
!lock btr [edx], eax
CompilerEndIf
!setc al
ProcedureReturn
EndProcedure
Global Flags = 0
Procedure MyThreadProc(Value)
Repeat
While AtomicBitSet(@Flags)
Delay(20)
Wend
For i = 1 To 10
Debug "Thread "+Str(Value)+" : "+Str(i)
Delay(100)
Next
AtomicBitReset(@Flags)
Delay(100)
ForEver
EndProcedure
CreateThread(@MyThreadProc(), 1)
CreateThread(@MyThreadProc(), 2)
Delay(10000)
If it previously was 0, you can proceed. If not, you can consider it locked.
At the end of the procedure you can reset the bit to indicate it is no longer locked.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
- RichAlgeni
- Addict
- Posts: 914
- Joined: Wed Sep 22, 2010 1:50 am
- Location: Bradenton, FL
Re: Does anyone have a 64 bit atomic increment decrement?
Ok, so we check the returned value, to see if the bit was changed by AtomicBitSet().
If it was, we are free to proceed with the locked resource.
Brilliant! Thanks so much Wilbert!!!
If it was, we are free to proceed with the locked resource.
Brilliant! Thanks so much Wilbert!!!
Re: Does anyone have a 64 bit atomic increment decrement?
Yes, if it previously was 0, it has changed from 0 to 1 so a lock was acquired.RichAlgeni wrote:Ok, so we check the returned value, to see if the bit was changed by AtomicBitSet().
If it was, we are free to proceed with the locked resource.
![Smile :)](./images/smilies/icon_smile.gif)
If you need to protect different resources, you can use a different bit index value.
With a quad value, you can protect 64 different resources.
The procedure itself supports a bit index from 0 - 255. If you want to use bit index 64 - 255, you can do it like this.
Code: Select all
Global *LockBits = AllocateMemory(32); allocate 256 bits
AtomicBitSet(*LockBits, 200)
AtomicBitReset(*LockBits, 200)
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
- RichAlgeni
- Addict
- Posts: 914
- Joined: Wed Sep 22, 2010 1:50 am
- Location: Bradenton, FL
Re: Does anyone have a 64 bit atomic increment decrement?
Brilliant! Thanks so much Wil!!!
I have 9 Windows Services programs that I am going to replace Slim Reader Writer with this.
I had high hopes for SRW. I don't understand how it could randomly fail like that.
So be it!
Thanks again!
Rich
I have 9 Windows Services programs that I am going to replace Slim Reader Writer with this.
I had high hopes for SRW. I don't understand how it could randomly fail like that.
So be it!
Thanks again!
Rich