InetClient

A thread is a basic unit of the CPU utilization. It is roughly equivalent to an independent program counter operating within a task. All threads within a task can access to all task resources. This facility is exploited in the java application.

Class InetClient extends Thread. It therefore has its own run( ).

In the run two new threads are started, the pullthread for pulling the files and the serverthread for servicing the clients. A ServerSocket is also initialized for the serverthread to listen for the client connections.

PullThread and the ServerThread as the names suggests, pulls and pushes the pages/files for the application. Both of them share the same memory space and therefore can access all the global variables.

The globalfiledbase - an array of strings is one such variable. At a given time it reflects the list of the files currently pulled from the web.

Carefully notice how the array is accessed by those threads.

During the PULL operation : -

The pull.pullcode( ) refers to globalfiledbase[ ] to detect and prevent a file being pulled again due to repeated links to the same file. After pulling a page/gif file it updates the globalfiledbase[ ] for future reference.

Format.clipper( ) refers to it to get the filenames represented by successive positions of the array of string.

Ins.advtinsert( ) opens the html files and inserts tags referencing the (.jpg) advertisments in the advt directory.

During the PUSH operation :-

Class ServerTest listens on the ServerSocket.

It accepts requests from and provides services to the client applications. With every client connection a new ServerTest instance/thread is created to service future clients while the current serverthread reads the globalfiledbase for the files to push to the client machines.

It is now clear that the globalfiledbase - an array of strings, holding the filenames is only read by the serverthread but is accessed and modified by the pullthread.

Two problems can be identified regarding the access to the array globalfiledbase. :

A. The above application can be said as a system of n+1 operating threads.

Here n = nconnections of the clients, 1 = pull thread.

Each of the thread has a segment of code, called the critical section in which the thread may either be writing to the comman array or reading from it. Now concurrent access to array either for writing or for reading must be mutually exclusive i.e. when one thread is executing in its critical section, no other thread is allowed to execute in its critical section.

Java uses the idea of monitors to synchronise access to data.

In java a synchronized statement acquires a monitor on behalf of the executing thread, then executes the body of the statement, and then releases the monitor. This way synchronization may reduce interference among different threads.

B. But observe that while the pull is in process and updation of the array is taking place, the concurrent push operations of the various server instances may work on the intermediate result of the pull operation, i.e. when the globalfiledbase is not fully updated to reflect all the new filenames. Therefore during a pull no server threads must be allowed to access the array and also during pushes no pull must be initiated.

As a result now at a particular instance EITHER a single pull thread OR n server threads can access the array (instead of n+1 threads as pointed out in A).

This is clearly a classical n_readers 1_writers problem with the array (globalfiledbase) being the comman data.

Note that the starvation of writer(pullthread) may happen if the readers(serverthreads) are generated for every client connection with the writer waiting for the readers to become zero before starting the pull.

A boolean variable 'claim' and integer 'nconnections' are declared as global. These can be said as metadata. Access (of n readers and one writer) to the array(globalfiledbase) can be decided on basis of the status of the metadata. Needless to say the accessing of the metadata itself must be synchronized. Claim is set if a pull is to be performed or is in progress. This flag is set/reset only by the pullthread.

Nconnections reflects the number of clients attached to the serverthread at a given time. This variable is modified only by the serverthread.

# Whenever a pull operation is to be performed the writer (pullthread) repeatedly

I. Sets the claim. This indicates that a pull is to be performed thereby inhibiting the server thread to service any future client connections.

II. It then accesses the variable nconnections. If nonzero-indicating push/es in progress the writer waits until notified by the last reader.

III. The writer thread after pulling the files, suitable formatting and inserting 'img src' tags in the .htm files for the advertisements, resets the claim so that in future new client connections can be serviced by the serverthreads.

IV. Sleeps for a specific period of time in which the URL contents may be updated.

# Whenever any client successfully establishes a connection with the reader (serverthread),

I. It checks to determine if a pull operation is in the waiting queue by checking the variable 'claim'. (This ensures that the writer starvation does not occur due to new readers accessing the array well past the pull time). If set, the client is gracefully disconnected. Else a new serverthread is spawned off to service future clients while the current serverthread does the following:

II. Increments the nconnections to reflect the number of readers,

III. Pushes the files onto the client,

IV. Decrements the nconnections variable.

V. The last reader thread invokes the notify method to wakeup the waiting writer thread.

This way pull and push modules are forced to work in co-ordination thereby moving a step further towards threadsafe programming.

// filename : InetClient.java import java.io.*; import java.lang.*; import java.awt.*; import java.net.*; import java.util.*; class InetClient extends Thread { static boolean connected_once = false; static long len_array[ ] = new long[1000]; //fileindex]; //* static int arrayindex = 0; static String globalfiledbase[ ] = new String[1000]; static String globalfiledbase_path[ ] = new String[1000]; static long f_date[ ] = new long[1000]; static boolean f_modified[ ]; static int fileindex = 0; static URL u; static boolean claim = false; static int nconnections = 0; static PullThred pt; static ServerSocket server; static ServerTest svrt; final static int SERVER_PORT = 8080; // OUR SERVER'S OWN PORT 8080 -- To make sure that little endian - big endian problem does not occur public static void print(String str) { sint.print(str); } public void run( ) //throws Exception { pt = new PullThred( ); svrt = new ServerTest( ); try{ sint.print("\nInitialising serversocket....."); server = new ServerSocket(SERVER_PORT) ; } catch(Exception x) { sint.print("\nerror in serversocket...."+x); } svrt.start( ); pt.start( ); sint.print("\n In ServerTestclass main"); // sint.print("In ServerTestclass main"); } //inetmain end public synchronized void aa( ) { try { sint.print("############ Pull on wait( )! #######"); wait( ); }catch(Exception w) { sint.print(w.toString( )); } } public synchronized void bb( ) { sint.print("########### Server notifying pull! ##########"); System.out.println("########### Server notifying pull! ##########"); notify( ); sint.print("\n############### after notify( ) #########\n"); // notifyAll( ); // sint.print("\n############# after notifyAll( ) ########\n"); } static synchronized void doclaim( ) { claim=true; } static synchronized void nowpull( ) { try { sint.print("\n############### in nowpull ##############\n"); pull.pullcode( ); f_date[2] = 777l; // delibrately changed so that only SPOR1.HTM should be pulled next time. connected_once = true; format.clipper( ); insert ins = new insert( ); System.out.println("before insert"); ins.advtinsert( ); System.out.println("after insert"); } catch(Exception e) { } } static synchronized void release( ) { claim = false; sint.print("\nclaim: "+claim); } static synchronized void pullwait( ) { try{ sint.print("\nwaiting.. claim: "+ claim+"\n"); Thread.sleep(45000); }catch(Exception ss){ sint.print("\nerror in sleep"); } } static synchronized boolean chkncon( ) { if(InetClient.nconnections == 0) return true; else return false; } }//class end class PullThred extends Thread { static InetClient p = new InetClient( );/////// public void run( ) { sint.print("\nin pullThread's run( ) "); while(true) { try{ InetClient.doclaim( ); if (InetClient.nconnections != 0) p.aa( ); // wait until nconn = 0. InetClient.nowpull( ); // pull and clip. InetClient.release( ); InetClient.pullwait( ); } catch(Exception e){ } } // END OF WHILE TRUE. } // end run. }// end class Thred

next >>

Index