If you have a program, that has many threads that access the same dynamic arrays of data, you need some mutex or CriticalSection. But mutex is slow- it has to enter global memory, and search for a string, specifying your mutex, and you have to wait for all. CriticalSections seem good, but accessing arrays of one million objects, and if you need to put an mutex in each of them, it all turns crap, as Andy Dick says :).
So, the easiest solution is this:
Yet, you can use only one bit to specify that the data is locked:
So, the easiest solution is this:
MyObject struct
IsAccessed db ?
MyData dd ? ;.....any data you want, you can have the structure as big as you want
MyObject ends
OnNewData proc me ; this is pointer to a MyObject structure
mov ebx,me
.while [ebx].MyObject.IsAccessed
push ebx
call SwitchToThread ; it is useless to do anything else!
pop ebx
.endw
mov [ebx].MyObject.IsAccessed,1
;.... do our processing on MyData here
mov ebx,me
mov [ebx].MyObject.IsAccessed,0 ; release the object
call SwitchToThread ; if this procedure is usually called by a low-priority thread, you should do this, to give immediate access to threads that are more important! Otherwise delete this line
ret
OnNewData endp
Yet, you can use only one bit to specify that the data is locked:
MyObject struct
Status db ?
MyData dd ? ;.....any data you want, you can have the structure as big as you want
MyObject ends
MY_OBJECT_STATUS_LOCKED equ 128
OnNewData proc me ; this is pointer to a MyObject structure
mov ebx,me
.while [ebx].MyObject.Status & MY_OBJECT_STATUS_LOCKED
push ebx
call SwitchToThread ; it is useless to do anything else!
pop ebx
.endw
or [ebx].MyObject.Status,MY_OBJECT_STATUS_LOCKED
;.... do our processing on MyData here
mov ebx,me
xor [ebx].MyObject.Status,MY_OBJECT_STATUS_LOCKED ; release the object
; you can use also:
;-------\
; and [ebx].MyObject.Status,( -1 - MY_OBJECT_STATUS_LOCKED)
;-------/
call SwitchToThread
ret
OnNewData endp
A lot of 286 code...
It will be better to consider bitRAKE's solution here:
http://www.asmcommunity.net/board/showthread.php?threadid=8796&perpage=15&highlight=xchg%20bitRAKE&pagenumber=1
Regards,
Lingo
It will be better to consider bitRAKE's solution here:
http://www.asmcommunity.net/board/showthread.php?threadid=8796&perpage=15&highlight=xchg%20bitRAKE&pagenumber=1
Regards,
Lingo
bitRake's algo is not good if the program knows the pointer, and has to save its data. For example, imagine some object that has a dynamic array with 700 objects, and it's being told to save the data into a file. So, xchg will make the program skip some important data. Or if you have a window with custom-drawn and managed windows inside (that do not use win API to work, but are managed by your program). You click with the mouse on this window over the area that is taken from virtual window Head (for instance). The program searches which window is in the Mouse_x::Mouse_y position, willing to send him a message that the mouse is down. The main window has its own array, where the children windows are registered, and if it doesn't find the target window, it does nothing. Imagine if that window is working in the moment the mouse button is pressed and we've deleted the window's pointer (unregister it). Nothing happens. Won't the user hate it?
So, if the data that we have will be saved, we should wait for the object to be released instead of skipping it ;). And with thread priorities set up, we can know which thread will be the first to switch to. I know it not from theory, but from a lot of practise. I've got a huge mainframe created using these mutex of mine, that works perfectly.
So, if the data that we have will be saved, we should wait for the object to be released instead of skipping it ;). And with thread priorities set up, we can know which thread will be the first to switch to. I know it not from theory, but from a lot of practise. I've got a huge mainframe created using these mutex of mine, that works perfectly.
Have you thought of what would happend if two threads came to the line:
mov .MyObject.IsAccessed,1
...at the same time? Both will get access!
mov .MyObject.IsAccessed,1
...at the same time? Both will get access!
How it can happen in 1 processor system if threads have different priorities?
gliptic: that hasn't happened even once for one month of testing. But if you want to ensure, if you have threads with same , normal priority, you should use
Thus, the two threads will absolutely never access the object at once
_beforeloop:
.while [ebx].MyObject.IsAccessed
push ebx
call SwitchToThread
pop ebx
.endw
inc [ebx].MyObject.IsAccessed
... a little code, a pause of two cycles
.if [ebx].MyObject.IsAccessed!=1
dec [ebx].MyObject.IsAccessed
jmp _beforeloop
.endif
Thus, the two threads will absolutely never access the object at once
And what about multiprocessor systems? ;)
gliptic: that hasn't happened even once for one month of testing. But if you want to ensure, if you have threads with same
Thus, the two threads will absolutely never access the object at once
IMHO, you missed lingo12's and gliptic's point. mov does not lock the memory automatically, while xchg with memory operand does. The important part is lock prefix. Without lock prefix, gliptic's argument is the expected result, and your experience is a pure luck -- or, you locked it before calling your code and you just forgot it. Anyhow, the code presented here is MT-unsafe, even under single CPU environment.
Gosh, sorry then. /me dumb . very, very dumb.
I guess I've really been lucky.
I guess I've really been lucky.
You can combine the best of both worlds and use this:
mov eax,TRUE
.while eax
xchg [esi].IsUsed,eax
.endw
no! you got the good idea, but I think the code is nothing like that. I think this is it:
(I hope I'm not wrong as usual)
@@:
mov al,1
mov ebx,me
xchg al,[ebx].MyObject.IsAccessed
or al,al
jz @F
call SwitchToThread
jmp @B
@@:
(I hope I'm not wrong as usual)
Try cmpxchg.
Ultrano, I don't really understand what the SwitchToThread proc does. My little snippet just waits until the object is available before continuing.
Switches to another thead. It's in fact the essence of my idea- you must not loop and try the data, because thus you just loop until the OS switches to another thead several times, and finally goes to the thread that unlocks the object. Why wait unnecessary? Immediately switch to the thead. Well, this is best for single-cpu systems only.
SwitchToThread is NT only. what about Sleep(0) ? or are there some consequences my dull mind hasn't picked up?
f0dder, there are some consequences that my dull mind hasn't picked up. I am using Win98SE ...
Anyway, gotta test all the thread functions today. SwitchToFiber might be ok.
Ah, at least I found one thing: in Sleep ():
Aww, sorry for wasting your time with crap
Anyway, gotta test all the thread functions today. SwitchToFiber might be ok.
Ah, at least I found one thing: in Sleep ():
A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.
Aww, sorry for wasting your time with crap
well, i was thinking whether there's something "bad" about Sleep(0) vs. SwitchToThread() in a situation like this?
no! you got the good idea, but I think the code is nothing like that. I think this is it:
@@:
mov al,1
mov ebx,me
xchg al,[ebx].MyObject.IsAccessed
or al,al
jz @F
call SwitchToThread
jmp @B
@@:
(I hope I'm not wrong as usual)
@@:
mov eax,1
mov ebx,me
cmpxchg eax,[ebx].MyObject.IsAccessed
jne @free
call SwitchToThread
jmp @B
@free: