Communicating between Object REXX threads

Communicating between Object REXX threads

Post by Bob Star » Thu, 29 Jul 2004 20:07:13

am attempting to write a set of Object REXX subroutines (win32) to
interface with databases. I am doing this because none of the database APIs
are currently thread-safe. The subroutine will queue the caller's request
for processing by a dedicated thread. It will wake up, read the arguments
off of a queue, perform the requested database operation, gather the
resulting variables and place them on another queue, and go back to waiting.

This routine makes a lot of use of the RXQUEUE() function, creating
temporary and permanant queues.
Yesterday, I discovered that when you use the RXQUEUE('SET', queuename)
call, it changes the default queue for all threads in the process, not just
the current thread. So the tool I am using to overcome my thread-safe
problems is itself not thread-safe.

Anyone have a suggestion on a good IPC mechanism between threads? The
database thread needs to be able to sit and wait, for perhaps minutes at a
time, then wake up quickly when it has work to do. I can have it sleep and
periodically wake up and look around, but I don't like that waseful and
delay-inducing approach.

I am thinking I will need to switch to having a separate process for the
database work, rather than a separate thread.

Here is the program that I used to demonstrate that this was going on, as a
tutorial to those of you who are wondering how you even create separate
parallel threads in ObjRexx:

/* REXX Exec rxQueTest1.rex Demonstrate that RxQueue() is not */
/* Thread-safe */

IF RXFUNCQUERY('SysLoadFuncs') = 1 THEN /* REXXUTIL functions avail? */
DO /* No, load them */
IF RxFuncAdd('SysLoadFuncs','REXXUTIL','SysLoadFuncs') <> 0
THEN DO; SAY 'Unable to load REXXUTIL functions'; EXIT; END
ELSE CALL SysLoadFuncs /* Load all REXXUTIL */

hSem = SysCreateMutexSem(SysQueryProcess('PID'))
If hSem = '' Then Do; Say 'Unable to create semaphore'; Exit; End

rc = SysRequestMutexSem(hSem,1)
If rc <> 0 Then Do; Say 'Unable to acquire semaphore, rc='rc; Exit; End

_async_obj = .Async~New /* Create Async class object */
_async_obj~Start(hSem) /* Launch background thread (same process)*/

Call SysSleep 0.5

/* Change the queue several times. Note that it changes for the other */
/* thread as well. */

queue1 = RXQUEUE('SET',queue1) /* Use new stack */
Call SysSleep 0.5

queue2 = RXQUEUE('SET',queue2) /* Use new stack */
Call SysSleep 0.5

queue3 = RXQUEUE('SET',queue3) /* Use new stack */
Call SysSleep 0.5

Say 'Press ENTER to exit'
pull .
rc = SysReleaseMutexSem(hSem)
say "Main: Exit"

::class Async

::method Start unguarded
/* This thread monitors the current rexx queue name, and puts */
/* out a message each time it changes. */
Reply /* This causes the creation of a new thread */

Use Arg hSem /* Extract handle to semaphore passed by caller*/
Say "Method start entered, Process ID="SysQueryProcess('PID')",",
"Thread ID="SysQueryProcess('TID')
prevQname = RxQueue('Get')
Do Forever
If RxQueue('Get') <> prevQname Then
Say "RxQueue('Get')="RxQueue('Get')", was" prevQname
prevQname = RxQueue('Get')

Communicating between Object REXX threads

Post by Michael Lu » Thu, 29 Jul 2004 22:25:39

Just as something for you to tinker with, you should be able to protect access to a .GLOBAL object with MutexSemaphores and share data back and forth that way. .GLOBAL is stored up in RXAPI so it is
global acorss multiple rexx.exe instances. I believe .LOCAL is "global" to a single rexx.exe instance, even which is running threads. (Rony if you are reading and I have posted incorrectly please
advise, or other ORexx PHD's as well.) The Object Rexx by Example book has lots of examples of these .GLOBAL and .LOCAL pools... I have yet to use them, and I have a class library built on ORexx, so
the nice thing is there is generally more power in ORexx than one uses to get a specific task completed.

Michael Lueck
Lueck Data Systems

Remove the upper case letters NOSPAM to contact me directly.


Communicating between Object REXX threads

Post by rexx » Fri, 30 Jul 2004 16:50:34

What database are you wanting to connect to ?

I'm currently in the process of making Rexx/SQL thread-safe if that
will help with your problem.

Cheers, Mark

Communicating between Object REXX threads

Post by Bob Star » Fri, 30 Jul 2004 18:29:50

DB2. Yes, I am using REXX/SQL, so the thread-safe version, when available,
will cause me to throw all of this code away. In the meantime, I am under
the gun to make it work, so I am plugging on. I'm using a wrapper layer, so
I won't have so much to do to throw it away. The wrapper layer is a single
RxSQL() function that wraps around the whole of REXX/SQL, and performs
common error checking.

It's winter where you live, right? Good weather for long days poring over C
code I hope! Good luck with that project!

Bob Stark

Communicating between Object REXX threads

Post by rony » Fri, 30 Jul 2004 19:10:30

Hmm, I am not aware of any environment called ".GLOBAL" under Object Rexx under Windows.

What you refer to seems to be the environment called ".ENVIRONMENT", which is system global under OS/2 (eComStation). I
have not been aware that that feature has been made available on any other operating system (just tried to run two
Object Rexx programs in two different Windows processes and sharing information/objects via .ENVIRONMENT, which did not

Maybe there is a switch to make that important behaviour available under Windows as well, but I have not found it.


P.S.: More on the Object Rexx environment under which Rexx programs execute can be found at:
< ;. There are two more short articles on Object Rexx, cf.
< ;.

Communicating between Object REXX threads

Post by Michael Lu » Sat, 31 Jul 2004 10:24:58

From the Windows 2.1.2 on-line help reference:

Environment Symbols
3. The local environment directory. The local environment includes process-specific objects such as the .INPUT and .OUTPUT objects. You can directly access the local environment directory by using
the .LOCAL environment symbol. (See The Local Environment Object (.LOCAL).)

4. The global environment directory. The global environment includes all permanent REXX objects such as the REXX supplied classes (.ARRAY and so on) and constants such as .TRUE and .FALSE. You can
directly access the global environment by using the .ENVIRONMENT environment symbol (see The Environment Object) or the VALUE built-in function (see VALUE) with a null string for the selector argument.

So .LOCAL was a good name, but .ENVIRONMENT was the correct name for what I thought was .GLOBAL.

Like I said, I have never used these, but they are in the help system for Win32 at least....???

Michael Lueck
Lueck Data Systems

Remove the upper case letters NOSPAM to contact me directly.

Communicating between Object REXX threads

Post by rony » Sat, 31 Jul 2004 19:50:33

Hmm, I wasn't clear enough:

- under OS/2 (eComstation)

- ".local" stores Rexx objects local to a process
- ".environment" stores Rexx objects global to all processes of OS/2 (i.e. "systemwide")
[as long as there is one Rexx program running in any process, ".environment" is
available and can contain Rexx objects placed there by Rexx programs in other
processes, which in the meantime may even have gone away!]

- under all other operating systems AFAIK

- ".local" stores Rexx objects local to a process
- ".environment" stores Rexx objects local to a process

Hope that helps,