CS360 Final -- December 11, 1999. Question 4: Answer and grading

15 points


Answer

#include < pthread.h >
#include < stdio.h >
#include "socketfun.h"

typedef struct {
  int fd;
  FILE *fout;
  int *nchars;
  pthread_mutex_t *lock;
} TStruct;

int read1000(int fd, char *chars)
{
  int so_far, i;

  so_far = 0;
  while(so_far < 1000) {
    i = read(fd, chars+so_far, 
             1000-so_far);
    if (i == 0) return 0;
    so_far += i;
  }
  return 1;
}

void *service_thread(void *arg)
{
  TStruct *t;
  char chars[1000];
  char output[20];

  t = (TStruct *) arg;

  if (read1000(t->fd, chars) == 1) {
    pthread_mutex_lock(t->lock);
    fwrite(chars, 1, 1000, t->fout);
    *t->nchars += 1000;
    sprintf(output, "%d\n", *t->nchars);
    pthread_mutex_unlock(t->lock);
    write(t->fd, output, strlen(output));
  }
  close(t->fd);
  free(t);
  return NULL;
}
main()
{
  int sock;
  int fd;
  FILE *fout;
  int nchars;
  pthread_t tid;
  TStruct *t;
  pthread_mutex_t lock;
  
  sock = serve_socket("cetus3a", 15000);
  if (sock < 0) 
    { perror("serve_socket"); exit(1); }

  fout = fopen("outfile", "w");
  if (fout == NULL) 
    { perror("fopen(outfile)"); exit(1); }

  nchars = 0;
  pthread_mutex_init(&lock, NULL);

  while (1) {
    fd = accept_connection(sock);

    t = (TStruct *) malloc(sizeof(TStruct));
    t->fd = fd;
    t->fout = fout;
    t->nchars = &nchars;
    t->lock = &lock;
    pthread_create(&tid, NULL, 
       service_thread, (void *)t);
  }
}
Part 1: I expected this to be straightforward. Allocate a TStruct, initialize it, and fork off a service_thread. This thread will call read1000() to read 1000 bytes, and if successful, it will lock the mutex, write the 1000 bytes and update nchars. Then it creates the output string, unlocks the mutex, and sends the output string to the client. Finally, it frees the TStruct and closes the file descriptor.

Nothing fancy. The original code works and is in q4.c, and the answer is in q4a.c. Try them out.

Part 2: The threaded code will improve performance under two conditions (and both conditions must be present):

  1. There are multiple simultaneous clients.
  2. Either the network connection to the client is poor, or the client does not send its 1000 bytes immediately. If the network connection is good and the client sends the 1000 bytes immediately, then the service_thread will never block, and there will be nothing gained by having multiple threads. It doesn't matter if the client reads the output quickly or not, because the operating system at the sender will buffer the output, and that write() call will never block.

Grading

Part 1 was worth 12 points, allocated as follows: I deducted points for other things. For example:

Part 2 You got two point for saying that it could service multiple simultaneous connections, but you needed to mention one of the other two issues (bad network or non-instantaneous sending of the 1000 bytes) to get the final point.