I want to create utility X. I want to call utility X in program A and program B. Program A runs, calls X, does work, then calls B. B will also call program X. This new X needs to start fresh and preserve state (file status, working storage) separate from the first instance. while B uses it. Eventually B will shut down X #2, and return to A, which needs X #1 to remember it's file state and working storage.
The manual says that you only have one instance of X in memory, and therefore only state, unless it is called in two different threads. I don't want to run A and B as separate threads. I could run X in it's own separate thread, but then I cannot call that instance again, because it's now in a separate thread - I would have to send messages back & forth instead of using the linkage area to pass back & forth.
Anyone know how to call a specific instance of X? (I was hoping the call would allow calling with thread handle already set, but that's not what the manual says)
#CALLSUBPROGRAMINSTANCESTATETHREADYou can't do what you want. But there is a simple workaround.
Start program B in a thread, and from program A, immediately wait for a message from B (effectively not using threads). When B is finished, send that message to A, allowing A to continue. In that way, X is running two separate instances.
Note that I have not tried this, but it should work.
I want to create utility X. I want to call utility X in program A and program B. Program A runs, calls X, does work, then calls B. B will also call program X. This new X needs to start fresh and preserve state (file status, working storage) separate from the first instance. while B uses it. Eventually B will shut down X #2, and return to A, which needs X #1 to remember it's file state and working storage.
The manual says that you only have one instance of X in memory, and therefore only state, unless it is called in two different threads. I don't want to run A and B as separate threads. I could run X in it's own separate thread, but then I cannot call that instance again, because it's now in a separate thread - I would have to send messages back & forth instead of using the linkage area to pass back & forth.
Anyone know how to call a specific instance of X? (I was hoping the call would allow calling with thread handle already set, but that's not what the manual says)
#CALLSUBPROGRAMINSTANCESTATETHREADHi
Sometimes we need the same and we use this workaround:
- Write the X utility
- Compile the X utility and have the X object (for now I call XOBJ)
- Copy the XOBJ in YOBJ
- Program A calls XOBJ
- Program B call YOBJ
Finally, if you're working in Linux environment, you can also use symbolic link instead of the copy of the object:
- Install the XOBJ file
- Link the XOBJ to the YOBJ
Since now, every time you update the XOBJ, the system updates also the YOBJ, so you don't need to do it by yourself
I want to create utility X. I want to call utility X in program A and program B. Program A runs, calls X, does work, then calls B. B will also call program X. This new X needs to start fresh and preserve state (file status, working storage) separate from the first instance. while B uses it. Eventually B will shut down X #2, and return to A, which needs X #1 to remember it's file state and working storage.
The manual says that you only have one instance of X in memory, and therefore only state, unless it is called in two different threads. I don't want to run A and B as separate threads. I could run X in it's own separate thread, but then I cannot call that instance again, because it's now in a separate thread - I would have to send messages back & forth instead of using the linkage area to pass back & forth.
Anyone know how to call a specific instance of X? (I was hoping the call would allow calling with thread handle already set, but that's not what the manual says)
#CALLSUBPROGRAMINSTANCESTATETHREADThank you both. I simplified the plan for my example, it could go beyond two instances, but both ideas could be used with a bit of work.
I plan to use the thread idea. The manual says that variables passed by reference are shared between caller and called. So I just have to, as suggested, call the program which should then go into a loop waiting for an incoming message. The caller then sends a message, eg the string "CALL", to the sub-program then immediately does a receive to wait for the subprogram to finish/exit. The subprogram gets the "call" message, does it's thing and sends back "DONE", and loops back to it's receive command. The caller can then resume and any changes the subprogram made to the using variables will be available. Cancel gets replaced by close thread.
The trick PiGi mentioned could become a managed thing - have a copy library that calls a utility to get the next "unused" version of the program name for the program being called. If that file doesn't exist yet, then the manager would link (or copy) the original to that name (XXXX, then XXXX1, then XXXX2 etc). Main program can call that unique name. Just remember to call a routine from the library to "cancel" the linked program so it can be marked as not-used. This has the advantage that each called program is unique and you can use the "USING" to pass parameters. The manager utility would leave the copies sitting around so they "cache". I would probbably put them into a work folder, so an update can purge the old copies of the updated programs, and the manager can just rebuild the cache.
I want to create utility X. I want to call utility X in program A and program B. Program A runs, calls X, does work, then calls B. B will also call program X. This new X needs to start fresh and preserve state (file status, working storage) separate from the first instance. while B uses it. Eventually B will shut down X #2, and return to A, which needs X #1 to remember it's file state and working storage.
The manual says that you only have one instance of X in memory, and therefore only state, unless it is called in two different threads. I don't want to run A and B as separate threads. I could run X in it's own separate thread, but then I cannot call that instance again, because it's now in a separate thread - I would have to send messages back & forth instead of using the linkage area to pass back & forth.
Anyone know how to call a specific instance of X? (I was hoping the call would allow calling with thread handle already set, but that's not what the manual says)
#CALLSUBPROGRAMINSTANCESTATETHREADTry this: program test_co_test runs two different istances of co_test. Limitation: the working-storage of co_test must be defined under a unique level 01 item
The "main" program test_co_test:
identification division.
program-id. test_co_test.
environment division.
configuration section.
source-computer. Lebedev_MESM.
object-computer. Lebedev_MESM.
special-names.
data division.
working-storage section.
78 main-pic value 65536.
01 par-size pic 9(08).
01 num-param pic 9(06) comp-1.
01 testHandle-a pointer.
01 testHandle-b pointer.
01 testHandle-c pointer.
01 buringoA pic x(32).
01 buringoB pic x(64).
01 buringoC pic x(128).
linkage section.
procedure division.
declaratives.
setup section. use at program start.
setup-ex. exit.
tearDown section. use at program end.
tearDown-ex. exit
end declaratives.
main-line.
stop " "
move "A" to buringoA
move "B" to buringoB
move "C" to buringoC
call "co_test" using testHandle-a | out new handle
call "co_test" using testHandle-b | out new handle
call "co_test" using testHandle-c | out new handle
call "co_test.setStringA" using testHandle-a
buringoA
call "co_test.setStringA" using testHandle-b
buringoB
call "co_test.setStringA" using testHandle-c
buringoC
move spaces to buringoA
move spaces to buringoB
move spaces to buringoC
call "co_test.getStringA" using testHandle-a
buringoA
call "co_test.getStringA" using testHandle-b
buringoB
call "co_test.getStringA" using testHandle-c
buringoC
call "co_test.dispose" using testHandle-a
call "co_test.dispose" using testHandle-b
call "co_test.dispose" using testHandle-c
stop " "
goback.
The subprogram co_test:
identification division.
program-id. co_test.
environment division.
configuration section.
source-computer. Lebedev_MESM.
object-computer. Lebedev_MESM.
special-names.
data division.
working-storage section.
78 main-pic value 65536.
01 par-size pic 9(08).
01 num-param pic 9(06) comp-1.
01 currentInstancePTR pointer.
01 propertyArea.
05 pa-stringA pic x(256).
05 pa-stringB pic x(256).
78 k-ll-propertyArea value length of propertyArea.
linkage section.
01 lk-instancePtr pointer.
01 lk-string pic x(main-pic).
procedure division using lk-instancePtr. | out per main (costruttore)
declaratives.
setup section. use at program start.
setup-ex. exit.
tearDown section. use at program end.
tearDown-ex. exit
end declaratives.
newInstance.
set lk-instancePtr to null
perform p-saveCurrentInstance
initialize propertyArea
call "M$ALLOC" using k-ll-propertyArea | in
lk-instancePtr | out
move lk-instancePtr to currentInstancePTR
goback returning 1
. |__________________________________________________________ endParagraph
entry "co_test.dispose" using lk-instancePtr. | inout
call "M$FREE" using lk-instancePtr
if lk-instancePtr = currentInstancePTR
move null to currentInstancePTR
end-if
move null to lk-instancePtr
goback returning 1
. |__________________________________________________________ endEntry
entry "co_test.setStringA" using lk-instancePtr | in
lk-string. | in
perform p-getCurrentInstance
call "c$paramsize" using 2 giving par-size
move lk-string (1:par-size) to pa-stringA
goback returning 1
. |__________________________________________________________ endEntry
entry "co_test.getStringA" using lk-instancePtr | in
lk-string. | out
perform p-getCurrentInstance
call "c$paramsize" using 2 giving par-size
move pa-stringA to lk-string (1:par-size)
goback returning 1
. |__________________________________________________________ endEntry
p-saveCurrentInstance.
if currentInstancePTR not = null
call "M$PUT" using currentInstancePTR | dataddress
propertyArea | data
k-ll-propertyArea | data size
1 | data-offset
end-if
. |__________________________________________________________ endParagraph
p-getCurrentInstance.
if lk-instancePtr = null
stop "null pointer exception (ahr ahr)"
goback returning 0
end-if
if lk-instancePtr not = currentInstancePTR
perform p-saveCurrentInstance
call "M$GET" using lk-instancePtr | dataddress
propertyArea | data
k-ll-propertyArea | data size
1 | data-offset
move lk-instancePtr to currentInstancePTR
end-if
. |__________________________________________________________ endParagraph