- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Recently, making my first attempt at multithreading andlooking for code to crib from, I found the following in the 'samplesadvancedwin32 hreads1.f90' unit, and would like to know why CopyMemory is used instead of the apparently simple 'Newcolor = color'. And also, why is LOC() used for one and not both memory locations?
Code:
recursive integer function ThreadProc(color) !DEC$ IF DEFINED(_X86_) !DEC$ ATTRIBUTES STDCALL, ALIAS :'_ThreadProc@4' :: ThreadProc !DEC$ ELSE !DEC$ ATTRIBUTES STDCALL, ALIAS :'ThreadProc' :: ThreadProc !DEC$ ENDIF use dfwina use threadin integer color integer*4 horizontal, vertical integer*4 ulx, uly type (T_RECT) rect1 integer*4 hDC type (T_SYSTEMTIME) Time integer*4 hBrush integer*4 width, height integer*4 NewColor call CopyMemory(LOC(NewColor),color,4)
Link Copied
3 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Because color is an address and NewColor is a variable.
There's plenty of room to play with (but also, to go wrong), with VALUE/REFERENCE/LOC (mis)matching. In this case:
* INTERFACE to CreateThread specifies VALUE for dummy argument argument (aka lpParameter in documentation)
* STDCALL in ThreadProc implies VALUE for dummy argument color.
* Thus, if in actual call to CreateThread, the corresponding actual argument is LOC(something), the stack also contains LOC(something).Then,dummy argumentcolor, when popped by value from stack, will also contain LOC(something).
Actually, I think the method in the sample is clumsiestof all-- nicer ways would be
1) pass something as actual argument, not LOC(something). Do normal assignment (NewColor=color)
2) pass LOC(something) as actual argument, but specify REFERENCE for dummy color. Do the normal assignment again.
General hint: alwaysask yourself"What will be placed on the stack (orstoredsomewhere)? When I pop it, how should I interpret it -- as a value or as an address?" Such situations are rather frequent with various callbacks and "lParam's" in Win32 programming. See this thread for an illustration of the trick -- LVI%lParam (a T_LVITEM) contains address of TYPE(something), while CompareFunc receives that same value by reference, thus retrieving correct contents. On the other hand, iType is passed by value and CompareFunc receives it by value (implied by STDCALL), thus again receiving correct value. (No need for clumsy Cray pointers).
Hope this helps,
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I admit to being almost completely at sea with REFERENCE and VALUE conventions., or at recognising which is applicable in any given situation....
It used to be simple: whenI wrote X=FUNCTION(Y,Z) where FUNCTION(Y,Z))
contained REAL*8 Y,Z , FUNCTION=Y*Z..END, I belived that what was actually passed to FUNCTION were the ADDRESSES or MEMORY LOCATIONS of Z and Y, and that the expression 'X=Y*Z' meant 'take the value found in memory location labelled Y and the value in memory location labelled Z, multiply them together and put the result into memory location that stores X'.
If, by mistake, I were to write 'X=FUNCTION(LOC(Y), LOC(Z)), then the arguments would be of the wrong type, given the FUNCTION definition, and I suppose, if an INTERFACE block for the function had been available(i.e. read)to the compiler (on its first run through the code)before it reached this statement, then it would recognise that LOC(X) is the wrong type of argument and say so.
If an arguments Z and Yare specified as BY VALUE, then does this mean that you can still write X=Z*Y in the function body?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It certainly takes an amount of mental effort (but practice makes wonders... as well as trial-and-error :-) ).
Historically, Fortran had always passed everything (as if) by reference (though pointers and assumed-shape arrays make a difference, but let's put that aside). However, VALUE and REFERENCE are language extensions which allows you to interface with C (or C-like languages). On the other hand, C(++) has clear distinction between integer type and pointer type, and clean (?) mechanism of "explicit interfaces" and you can not mix one for another. Fortran, OTOH,does not have an "address" type so (esp. on a 32-bit system) you may exchange INTEGERs and addresses freely (which can lead to troubles).
If, by mistake, I were to write 'X=FUNCTION(LOC(Y), LOC(Z)), then the arguments would be of the wrong type, given the FUNCTION definition, and I suppose, if an INTERFACE block for the function had been available(i.e. read)to the compiler (on its first run through the code)before it reached this statement, then it would recognise that LOC(X) is the wrong type of argument and say so.
Well, indeed. The mixup, as I said above, can primarily occur with integers. That's where you need the mental effort.
Still, you can cheat :-). The following works:
Code:
PROGRAM Cheat_But_Works INTERFACE REAL FUNCTION F(X, Y) INTEGER(INT_PTR_KIND()):: X, Y !DEC$ATTRIBUTES VALUE:: X, Y END FUNCTION END INTERFACE X = 1; Y = 2 Z = F(LOC(X), LOC(Y)) END PROGRAM Cheat_But_Works !=================================== REAL FUNCTION F(X, Y) F = X*Y END FUNCTION F
(I purposefully used INT_PTR_KIND() to emphasize the type. Alas, INT_PTR_KIND() is 4 on IA32 so you may interchange it with INTEGER(4). Some J3 F90 standard commitee members expressed regrets because they haven't made KINDs a separate datatype from integers at the time -- doing so would increase type-safety although it could make the code more verbose).
If an arguments Z and Yare specified as BY VALUE, then does this mean that you can still write X=Z*Y in the function body?
Yes, but you cannot make a VALUE argument INTENT(OUT). (And I'm lazy to check, but I think you will get a compile-time error if you try to). VALUE is almost exclusively used only for 4-byte entities (INTEGERs, REALs and LOGICALs); even in C (and especially in API), structs (usually) and arrays (always) are passed by reference.
Jugoslav

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page