I read through the newsgroup and have searched the web and even read the
Compaq VF user's guide:-) but I have not found an answer. Can someone
please explain the various ways to share the common block within VF?
Thank you.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----
Well, that's not so easy. AFAIK Windows does not allow common block
sharing among different processes. One possibility is to put the shared
commons into a dll, DLLEXPORT them from there, and DLLIMPORT them from
exes. However, you will have to find a way (I don't know) how to specify
#pragma data_seg(".shared") in CVF in order to specify that the data
segment in question is shared amongst all instances of the dll.
See Q125677 in MSDN and related links
(http://support.microsoft.com/default.aspx?scid=kb;EN-US;q125677)
An alternative with potentially less gotchas (but requires more
changes in the source) is to use file mappings. There's a convenient
wrapper ShareBufferWin32.f90 at http://www.fortranlib.com/freesoft.htm.
However, the gotcha here is that you can't say "here's my common block
-- share it", but only, "gimme a shared memory of size n". In other
words, you have to find a way to map the common to given memory block.
Since commons cannot be instantiated at will, you will have to:
- convert the common block to a derived TYPE, e.g. T_DATAPOOL
- declare a global pointer, say T, of type T_DATAPOOL:
type(T_DATAPOOL), pointer: T. Put it in a module, say
M_DATAPOOL.
- now, you can map T to an address returned by CreateShareBuffer.
To do it, you have to (ab)use CVF feature that a scalar pointer
is just an address (void* or LPVOID). So, you have to "lie" to the
compiler that bufferAddress argument should be a pointer to a T_DATAPOOL,
not an integer. Put the following interfaces into a module, say
M_SHARED:
interface
subroutine CreateShareBuffer(bufferName,numBytes,bufferAddress,iRetcode)
USE M_DATAPOOL
character(*), intent(in) :: bufferName
integer, intent(in) :: numBytes
integer, intent(out) :: iRetcode
TYPE(T_DATAPOOL), POINTER:: bufferAddress
end subroutine
end interface
Do so for every routine containing bufferAddress from ShareBufferWin32.f90.
- Now, call CreateShareBuffer in the "first" exe. On startup of every exe, call
OpenShareBuffer like:
USE M_DATAPOOL
USE M_SHARED
call OpenShareBuffer("MyShareBuffer", T, iErr)
The greatest pain, I'm affraid, is that you'll have to replace all
occurrences of every variable X from the datapool with T%X.
--
Jugoslav
___________
www.geocities.com/jdujic
Don't forget to closesharebuffer at conclusion of each "slave" exe.
This would normally be done in the "master" exe. So if possible, the
"master" exe should be responsible for terminating the other exes in an
orderly manner. I probably should investigate supplemental utilities to
initiate/terminate other specific exes and include them (well initiate
is usually readily available already). My first thought is to be afraid
of publicly posting a terminate example.
>
> --
> Jugoslav
> ___________
> www.geocities.com/jdujic
--
Gary Scott
mailto:gary...@ev1.net
Fortran Library
http://www.fortranlib.com
Support the GNU Fortran G95 Project: http://g95.sourceforge.net
Ah yes, datapool
I had that on SDS-SIGMA5/7 fortran circa 1967
however, in the present world I would recommend a re-think of the
separate console apps, just merge them into one.
you might be surprised that you dont need to run them asynchronously,
but if you do, they become threads to be controlled by your NEW exec
module datapool
...............
end module datapool
program merged_console_apps_main_exec
use datapool
end program
subroutine console_app1()
use datapool
etc.
Oops, and of course I meant to say to delete it at the end as well to
avoid a memory leak.
A side issue, Gary -- may I offer a suggestion? I think the code would be
much more useful if you declare the bufferAddress to be a POINTER with
no argument checking. It's a cludge, I know, but at least in this way
you keep all the "ugliness" withing ShareBufferWin32 code, leaving user
side relatively clean. It also requires redeclaration of API interfaces.
All user has to do is to pass a *scalar pointer variable* as lpData,
and it's associated with the address returned from the API. No troubles
with Cray pointers.
If I may post a similar example of my own (wrapper around GetProp API,
which returns a LPVOID, similarly as MapViewOfFile). (Purists, please
turn your heads on the other side :-)):
!======================================================================
LOGICAL FUNCTION XGetWindowData(xWnd, lpData, sDataID)
TYPE(X_WINDOW), INTENT(IN):: xWnd
!DEC$ATTRIBUTES NO_ARG_CHECK:: lpData
INTEGER, POINTER:: lpData
CHARACTER(*), OPTIONAL, INTENT(IN):: sDataID
INTERFACE
FUNCTION GetProp (hWnd ,lpString)
USE XFTTYPES
INTEGER, POINTER:: GetProp
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_GetPropA@8' :: GetProp
!DEC$ ATTRIBUTES REFERENCE :: lpString
INTEGER hWnd
CHARACTER(*) lpString
END FUNCTION GetProp
END INTERFACE
IF (PRESENT(sDataID)) THEN
lpData => GetProp(xWnd%hWnd, TRIM(sDataID)//CHAR(0))
ELSE
lpData => GetProp(xWnd%hWnd, "XDATA"C)
END IF
XGetWindowData = ASSOCIATED(lpData)
END FUNCTION XGetWindowData
--
Jugoslav
___________
www.geocities.com/jdujic
I thought of that when designing it but I never thought it through. I
wasn't completely sure of whether that would somehow limit flexibility.
I will consider a change.
<snip>
I remember how it was supposed to work now. The main exe simply sets a
shared variable "kill flag" and the other exes monitor it and
self-terminate when required. That should usually work although
sometimes you might need to force a termination.
I currently have the software running as one console application, similar to
the method David Frank described below. However, I have been reading about
the threads, specifically CreateThread and ExitThread using CVF. I looked
at some of the sample CVF programs such as the PEEKQQ example. Can anyone
expound on the pros and cons of CreateThread?
I would also like to set the priority and rate at which the thread executes.
For example some of the threads need to execute at 60 Hz while other threads
will execute at 30 Hz, 15 Hz and 7 Hz. Any suggestions for scheduling the
frequency of execution?
Thank you.
"David Frank" <dave_...@hotmail.com> wrote in message
news:dEPTa.12890$BB6.1...@twister.tampabay.rr.com...
Since you are adapting my suggestion, I will share SOME details how I
setup my realtime program RT_VIEW.
But the CVF online forum is the #1 site to technical questions.
You can run all threads synchronously at same NORMAL priority since it
is higher than exec task default IDLE priority, and since your tasks
are multiples of lowest frequency 7.5hz
re: peekqq
You probably want to monitor/execute commands linked to operator
single keystrokes, and to do that without interfering with your higher
priority tasks, you need a keyboard thread that responds to each
keystroke.
A self-scheduler would just put a
Resume 30hz task at end of alternate 60hz tasks,
Resume 15hz task at end of alternate 30hz tasks,
Resume 7.5hz task at end of alternate 15hz tasks,
Below is clipped from my RT_VIEW program which monitors stock-index
futures prices from CME (Chicago Mercantile Exchange) and plots them
for daytrading, plus other real-time site happenings around the net as
long as I can decode the site's raw html formats for realtime display
and plotting.
! - - - create/connect threads suspended at control loop
priority - - -
hKeyReadProc = CreateThread( 0, 0, KeyReadProc, 0, CREATE_SUSPENDED,
n )
hNetReadProc = CreateThread( 0, 0, NetReadProc, 0, CREATE_SUSPENDED,
n )
n = SetThreadPriority (hKeyReadProc, THREAD_PRIORITY_NORMAL )
n = SetThreadPriority (hNetReadProc, THREAD_PRIORITY_NORMAL )
n = ResumeThread (hKeyReadProc) ! activate keyboard
Note: KeyReadProc(), NetReadProc() are just normal subroutines with
NO args that become keyboard, internet read execs and have access to
exec's data module that control their functions and provides variable
scalar,array storage.
"Paul Curtis" <pcu...@kiltel.com> wrote in message news:3F2A850E...@kiltel.com...
Ohh, that subject again...
The discussion you refer to was actually repeated at the Forum recently
with all acters (Paul, Gerry Thomas [or was it Gary Scott? -- I tend
to mix two of them and I'm lazy now to search back] & myself) basically
staying on their positions. At the end, I took a 3rd-party tool
(www.memoryvalidator.com) and tested CreateThread on a sample application
and it indeed shown a small leakage on a call to a RTL function
(IIRC, it was 24 bytes on RANDOM_NUMBER). Then, I took Paul's translation
of _beginthreadex, but the same leakage was present there as well.
I took these results as inconclusive for either side of the argument
so I didn't posted them at the time. I'm certainly not competent enough to
interpret Memory Validator's results, since it shown other leaks of unknown
origin, on a small application I was very careful with to release everything --
CloseHandle, deallocate, DlgUnInit. Frankly, I wasn't interested in
the subject enough to bug Stephen Kelett (author of the MV) further. I'd
say that Paul's qualification that CreateThread is "unusable" is kinda
overstatement -- such small leakage, although a bit embarrasing, is
not likely to create problems on anything less than an always active
multi-user server (i.e. creating a huge number of threads and being
active 24/7).
--
Jugoslav
___________
www.geocities.com/jdujic
[...]
The root of the problem with CVF multithreading is that its runtime
doesn't properly initialize itself. This is why with CVF you'll have
memory leakage in multithreading irrespective of whether you spawn
threads via CreateThread or _beginthreadex. There is a simple
workaround but I don't feel like mentioning it again.
I'll use my formal appellation so you'll be less confused.
Dr.G.F. Thomas