![]() |
The NetRexx Tutorial
![]() |
All modern operating systems are multi-tasking. This means than more than one program can concurrently run on the system at the same time. At least, this is how the user(s) perceive it: the operating system is responsible to allocate CPU cycles to the various processes, giving the impression that every process has, by itself, an entire CPU available.
In a multi-threaded system, you can divide each process into several components. These components are called threads or light weight processes.
In this chapter we will analyse how we can have multiple threads running within our programs.
A thread is a component of a process. A thread is synonim of light weight process. Each thread executes a sequential set of instructions. The result of several threads running in parallel is a concurrent process.
| concurrent | ---------+-------> thread 1 | process | | > Instruction 1.1 | > Instruction 1.2 | (...) | > Instruction 1.n | +-------> thread 2 | > Instruction 2.1 | > Instruction 2.2 | (...) | > Instruction 2.n (...) | +-------> thread N > Instruction N.1 > Instruction N.2 (...) > Instruction N.n
As we saw, threads allow to run multiple instances of the same process on your machine. But, you may ask, what's the real interest in doing this, if my machine has just one CPU? Aren't those processes going to compete for this unique resource?
While it is true that CPU tied processes will benefit from a multiprocessor H/W environment, it is also true that, on many OS (notably UNIX and Windows/NT) the I/O subsystem is usually decoupled from the main CPU, so you can imagine to split your program in 2 parts: one which deals with the I/O, and one that deals with the CPU intensive work. A natural example is when you load a WEB containing pictures using Netscape. The text is immediately retrieved and the pictures are loaded while you can read, scroll, and do any other operation on the page itself (even if still incomplete). In principle, any picture retrieval can be a separate thread.
A daemon is a process that runs on your system and acts as a server. As we will analyse in the next chapter, a daemon waits on a socket port for work to do. When it receives a request from a client, he dispatches the request. If the daemon is single-threaded he will not be capable to accept and serve other requests, till he has not finished the one is serving. Using threads, you'll be capable to concurrently serve many requests.
SERVER SERVER THREAD (...) loop forever wait request dispatch request +-------> start thread execute request answer client end thread (...) end
Another application of threads is monitoring of certain process. Some applications might hung (for a network problem, for example). You might want to put an external timeout to such occurrences.
If you are a C (or C++) programmer working on UNIX platforms, and you want to create a process running in parallel with your main process, you would write something like:
+----------------------------------------------------------------------+ | /* example in Regina UNIX REXX |01 | */ |02 | (...) |03 | |04 | /* issue the fork |05 | */ |06 | i = fork() |07 | |08 | if i > 0 then |09 | do |10 | /* This is the parent process |11 | */ |12 | say '(parent) Waiting.' |13 | rc = waitpid(i) |14 | say '(parent) Wait rc:' rc'.' |15 | end |16 | else |17 | do |18 | /* This is the children |19 | */ |20 | 'sleep 1' |21 | say '(child) Starting. Going to sleep.' |22 | 'sleep 2' |23 | say '(child) Ending now.' |24 | end |25 | exit 0 |26 +----------------------------------------------------------------------+ forkex1.rex | ![]() |
In NetRexx, like in Java, the approach is totally different. The above example will be written like:
+----------------------------------------------------------------------+ | -- package: thrt1 |01 | -- version: 1.000 beta |02 | -- date: 02 APR 1998 |03 | -- author: P.A.Marchesini |04 | -- copyright: (c) P.A.MArchesini, 1998 |05 | -- latest vers.: http://wwwcn.cern.ch/news/netrexx |06 | -- |07 | -- |08 | class thrt0 |09 | properties public |10 | |11 | -- method......: main |12 | -- purpose.....: timeout test |13 | -- |14 | method main(args=String[]) public static |15 | arg = rexx(args) |16 | arg = arg |17 | |18 | say 'MAIN starts now.' |19 | child = thrt0handler() |20 | child.start() |21 | child.join() |22 | say 'MAIN ends' |23 | exit 0 |24 | |25 | -- method......: thrt0handler |26 | -- purpose.....: |27 | -- |28 | class thrt0handler extends Thread |29 | properties private |30 | |31 | method thrt0handler() |32 | |33 | method run() public |34 | say 'CHILD starts.' |35 | do |36 | sleep(2000) |37 | catch e = interruptedException |38 | say 'Got: "'e'".' |39 | end |40 | say 'CHILD ends.' |41 +----------------------------------------------------------------------+ thrt0.nrx | ![]() |
It is always a good practice to put a timeout on certain commands that you might issue inside your program. Infact, especially in a networked environment, a lot of things might "go wrong", and the program itself might hung forever.
The following example will show how to implement a timeout on a command that you issue from the command line.
+----------------------------------------------------------------------+ | -- package: thrt1 |01 | -- version: 1.000 beta |02 | -- date: 02 APR 1998 |03 | -- author: P.A.Marchesini |04 | -- copyright: (c) P.A.MArchesini, 1998 |05 | -- latest vers.: http://wwwcn.cern.ch/news/netrexx |06 | -- |07 | -- |08 | class thrt1 |09 | properties public |10 | |11 | -- method......: main |12 | -- purpose.....: timeout test |13 | -- |14 | method main(args=String[]) public static |15 | arg = rexx(args) |16 | parse arg timeout command |17 | if timeout = " | command = " then |18 | do |19 | say 'Missing arguments.' |20 | say 'usage : java thrt1 TIMEOUT_IN_SEC COMMAND' |21 | say 'example: java thrt1 5 sleep 6' |22 | exit 1 |23 | end |24 | timeout = timeout*1000 |25 | |26 | say 'MAIN starts now.' |27 | child = thrt1handler(command) |28 | child.start() |29 | child.join(timeout) |30 | if child.isAlive() |31 | then |32 | do |33 | say 'Children still alive. Killing it now.' |34 | child.stop() |35 | if child.isAlive() |36 | then say 'ERROR: stop() did not work.' |37 | else say 'OK: child killed.' |38 | end |39 | else say 'Children finished before timeout.' |40 | |41 | say 'MAIN ends' |42 | exit 0 |43 | |44 | -- method......: thrt1handler |45 | -- purpose.....: |46 | -- |47 | class thrt1handler extends Thread |48 | properties private |49 | command |50 | |51 | method thrt1handler(cmd=rexx) |52 | command = cmd |53 | |54 | method run() public |55 | say 'CHILD starts "'command'".' |56 | out = xexec(command) |57 | out = out |58 | say 'CHILD ends "'command'".' |59 +----------------------------------------------------------------------+ thrt1.nrx | ![]() |
You can try out the code typing:
# no timeout shown here $ java thrt1 5 sleep 4 # timeout shown here $ java thrt1 5 sleep 6
*** This section is:*** and will be available in next releases