CSC352 Homework 3 Solution 2013
--D. Thiebaut (talk) 14:44, 25 October 2013 (EDT)
The solution to the optional problem is posted, as it applies also to the first part of the assignment.
doHomework3_N_images.sh
#!/bin/bash
#
# doHomework3_N_images.sh
# Emily Flynn
# CSC 352
# 10/23/2013
#
# Script that runs master/worker routine for image resizing with N
# images and N workers. It receives a list of images as parameters and
# creates a worker (workerN) to receive each. An in and output pipe is
# created for each image/worker, and is canoncially named by the
# proper prefix and an index for the image/worker. The image names are
# passed to a java program (MasterN) that will communicate with all
# the workers.
#
# Note: in the future this program should be re-worked so that there
# can be a user specified number of workers not necessarily equal to
# the number of images. I did not get a chance to do this, but I left
# in functionality for the workers to process multiple images for when
# this is fixed.
#
# To run:
# ./doHomework3_N_images.sh <image1> <image2> ... <imageN>
N="$#" # number of args is number of images, workers
TO_WORKER_PREFIX="temp_toWorker"
TO_MASTER_PREFIX="temp_toMaster"
# remove resized images - uncomment this if you are running multiple
# times for testing purposes, will get rid of previous resized images
# so that there is no confusion
#rm -f *_resized*
# compile programs
javac MasterN.java
gcc -o workerN workerN.c
# create N canonically named worker,master pipes
for ((i=0; i<$N;i++))
do
# create a worker pipe
worker_pipe=${TO_WORKER_PREFIX}${i}
mkfifo $worker_pipe
# create a master pipe
master_pipe=${TO_MASTER_PREFIX}${i}
mkfifo $master_pipe
done
# run the MasterN program with the images as parameters
java MasterN $@ &
# invoke N workers with the proper pipes
for ((i=0; i<$N;i++))
do
# run workerN.c with the worker and master pipes as parameters
./workerN ${TO_WORKER_PREFIX}${i} ${TO_MASTER_PREFIX}${i} &
done
# remove pipes to clean up directory
rm -f temp_*
exit 0;
workerN.c
/*
* workerN.c
* Emily Flynn
* CSC 352
* 10/23/2013
*
* This program receives names of image(s) from a fifo from the java
* MasterN program, resizes each by 50% using ImageMagick, and runs
* identify on each. It names the resized images by the original name
* followed by the suffix "_resized". It then sends back identify
* information through a fifo to the MasterN program. The parameters
* for this program are the name of the inPipe, followed by the name
* of the outPipe:
* ./workerN <inPipe> <outPipe>
*
* This program is the same as worker1.c except it receives the in and
* out pipe names as parameters instead of having them hard-coded.
*
* Use the script doHomework3_N_images.sh to compile and run this
* program.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXDIM 1000
/**
* Function to generate a new name for an image by appending
* "_resized" after the original image name before the file extension.
*
* newName - pointer to the new name
* origName - pointer to the original name
*/
void generateNewName(char* newName, char* origName){
char *p;
// find the period character in the original name
p = strchr(origName, '.');
// error message if there is no period
if (p == NULL){
printf("Error! Image names are not formatted correctly.\n");
exit(-1);
}
// temporarily replace the period character with an end of string
*p = '\0';
// copy in the first part of the image name (before the period)
strcpy(newName, origName);
strcat(newName, "_resized"); // add resized to the image name
// restore the period character
*p = '.';
// append the rest of the image name to the new name
strcat(newName, p);
return;
}
/**
* Main method for running worker program. Parameters specify names
* for in and out pipes. Reads in image names from a pipe, resizes them
* and and runs identify on them. Then writes the output to another
* pipe for the master program to read.
*
* parameters: inPipe, outPipe
*/
int main(int argc, const char** argv){
int i, numFiles;
FILE *fp_in, *fp_out, *pf; // pipes for in, out, and command line
char imageArray[10][40]; // an array for holding the images (names
// are ltd to 40 char, and ltd to 10 images
// total)
char newname[47]; // new name of a particular image
char command[120]; // ImageMagick Command
char result[MAXDIM]; // output of running identify
const char* inFile; // in pipe name
const char* outFile; // out pipe name
// in/out pipe names come from the parameters
inFile = argv[1];
outFile = argv[2];
// open the pipe for reading in the image names
fp_in = fopen(inFile, "r");
i=0; // counter
// read in the image names and put them in an array
while (!feof(fp_in)){
fscanf(fp_in, "%s", imageArray[i]);
i++;
}
fclose(fp_in); // close the input pipe
numFiles = i; // keep track of the number of files
// open the pipe for writing out the image names
fp_out = fopen(outFile, "w+");
// loop through all the images
for (i=0; i<numFiles; i++){
// generate a new name for the current image
generateNewName(newname, imageArray[i]);
// construct the command to resize the image
strcpy( command, "convert ");
strcat( command, imageArray[i]);
strcat( command, " -resize 50% ");
strcat( command, newname);
strcat( command, " && "); // execute next command if this one succeeds
// add the command to run identify
strcat( command, "identify " );
strcat( command, newname);
// run the command
pf = popen(command, "r");
if (!pf){
fprintf(stderr, "Could not open pipe for command line output.\n");
}
// grab the data from running identify
fgets(result, MAXDIM, pf);
// write out the output of running identify to the out pipe
fprintf(fp_out, "%s", result);
}
// close the out pipe
fclose(fp_out);
return(0);
}
MasterN.java
/*
* MasterN.java
* Emily Flynn
* CSC 352
* 10/23/2013
*
* This program sends the name of each image it is passed as a
* parameter to a different worker through a fifo and then receives
* information on the resized images from a fifo from each of the
* workers and prints this information to the screen. Fifos are
* canonically named with indices, and match those created by the
* script doHomework3_N_workers.sh.
*
*/
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.FileReader;
import java.io.File;
public class MasterN {
// prefixes for worker and master pipe names
private static final String PREFIX_FIFO_OUT = "temp_toWorker";
private static final String PREFIX_FIFO_IN = "temp_toMaster";
/**
* Main method for the Master program. Writes out the names of the
* images into out pipes, then reads in response from in pipes.
*
* @param args - the list of images
*/
public static void main(String[] args){
// keep track of the number of images
int numImages = args.length;
// holders for names for in and out pipes
String outName;
String inName;
// write out the names of all of the images into the outpipes
// one per out pipe, with each named with the prefix followed
// by an index
for (int i=0; i<numImages; i++){
outName = PREFIX_FIFO_OUT + Integer.toString(i);
try {
BufferedWriter out = new BufferedWriter(new FileWriter(outName));
out.write(args[i]);
out.close();
} catch (IOException e){
System.out.println("IO Exception at buffered write index "+i+".");
System.exit(-1);
}
}
// create an array of bufferedReaders, one for reading information
// from each worker
BufferedReader in[] = new BufferedReader[numImages];
// also create an array of booleans to keep track of whether
// Master is done reading from the fifos
boolean finish[] = new boolean[numImages];
for (int i=0; i < numImages; i++){
finish[i] = false;
inName = PREFIX_FIFO_IN + Integer.toString(i);
try {
in[i] = new BufferedReader(new FileReader(inName));
} catch (IOException e){
System.out.println("Error creating buffered reader");
System.exit(-1);
}
}
int numFinish = 0; // count the number that are finished
try {
// loop until all of the pipes have been read (1 per image)
while (numFinish != numImages){
// loop through all the pipes
for (int i=0; i<numImages; i++){
// if this particular pipe is not finished
if (!finish[i]){
// check if it is ready
if (in[i].ready()){
// if it is, read in the information in the pipe
String line = in[i].readLine();
while (line != null){
System.out.println(line);
line = in[i].readLine();
}
// indicate the pipe has been read from,
// close it, and increment the number of pipes finished
finish[i] = true;
in[i].close();
numFinish++;
}
}
}
}
} catch (IOException e){
System.out.println("Error in reading from pipes.");
System.exit(-1);
}
System.exit(0);
}
}