Friday, November 27, 2009

17.6 Sequential Tasks



[ Team LiB ]






17.6 Sequential Tasks


This section describes the behavior of the dispatcher when the child task has both input and output. Although the dispatcher handles only one task at a time, it must monitor two input file descriptors. Complete Section 17.5 before starting this part.


The dispatcher keeps information about the child task in the tasks array. For simplicity, the discussion refers to members of the ntpvm_task_t array such as readfd without their qualifying structure. Implement the tasks array as an object with appropriate access functions. The tasks array and its access functions should be in a file separate from the dispatcher main program. The array and its access functions are referred to as the tasks object, and an individual element of the tasks array is referred to as an entry of the tasks object. For this part, we only allow one task at a time, so the tasks object does not need an array of tasks.


Figure 17.8 suggests the structure of threaded NTPVM dispatcher. An input thread monitors standard input and processes the incoming packets. An output thread monitors the readfd descriptor for input from the child task and writes this information to standard output.



Figure 17.8. Schematic of a threaded NTPVM dispatcher for a single task.






The input and output threads share the tasks object and must synchronize their access to this structure. One possible approach for synchronizing threads is to use a mutex lock to protect the entire tasks object. This choice cuts down on the potential parallelism because only one thread at a time can access the tasks object. Since mutex locks are low cost, we use a mutex lock for each element of the tasks array.



17.6.1 The input thread


The input thread monitors standard input and takes action according to the input it receives. Write an input function that executes the following steps in a loop until it encounters an end-of-file on standard input.





  1. Read a packet from standard input by using getpacket.


  2. Process the packet.



After falling through the loop, close writefd and call pthread_exit.


Processing a packet depends on the packet type.



NEWTASK






  1. If a child task is already executing, discard the packet and output an error message.


  2. Otherwise, if no child task exists, create two pipes to handle the task's input and output.


  3. Update the tasks object, and fork a child. The child should redirect its standard input and output to the pipes and use the makeargv function of Program 2.2 to construct the argument array before calling execvp to execute the command given in the packet.


  4. Create a detached output thread by calling pthread_create. Pass a key for the tasks entry of this task as an argument to the output thread. The key is just the index of the appropriate tasks array entry.




DATA





  1. If the packet's communication and task IDs don't match those of the executing task or if the task's endinput is true, output an error message and discard the packet.


  2. Otherwise, copy the data portion to writefd.


  3. Update the recvpackets and recvbytes members of the appropriate task entry of the tasks object.




DONE





  1. If the packet's computation and task IDs do not match those of the executing task, output an error message and discard the packet.


  2. Otherwise, close the writefd descriptor if it is still open.


  3. Set the endinput member for this task entry.



BROADCAST, BARRIER or TERMINATE





  1. Output an error message.


  2. Discard the packet.




Exercise 17.9

When a process that contains multiple threads creates a child by calling fork, how many threads exist in the child?


Answer:


Although fork creates a copy of the process, the child does not inherit the threads of the parent. POSIX specifies that the child has only one thread of execution�the thread that called fork.





17.6.2 The output thread


The output thread handles input from the readfd descriptor of a particular task. The output thread receives a tasks object key to the task it monitors as a parameter. Write an output function that executes the following steps in a loop until it encounters an end-of-file on readfd.






  1. Read data from readfd.


  2. Call putpacket to construct a DATA packet and send it to standard output.


  3. Update the sentpackets and sentbytes members of the appropriate task entry in the tasks object.



After falling through the loop because of an end-of-file or an error on readfd, the output thread does the following.









  1. Close the readfd and writefd descriptors for the task.


  2. Execute wait for the child task.


  3. Send a DONE packet with the appropriate computation and task IDs to standard output.


  4. Output information about the finished task to standard error or to the remote logger. Include the computation ID, the task ID, the total bytes sent by the task, the total packets sent by the task, the total bytes received by the task and the total packets received by the task.


  5. Deactivate the task entry by setting the computation ID to �


  6. Call pthread_exit.



Test the program by starting tasks to execute various cat and ls -l commands. Try other filters such as sort to test the command-line parsing. For this part you should not enter a new command until the previous command has completed.







    [ Team LiB ]



    No comments: