CS360 Midterm -- May 2, 2002

Answer to Question 4

This is much easier with threads than without. Each thread simply has to read 20 bytes from the connection, then grab a mutex, add one to the line number, print out the line, release the mutex and then continue.

You could have done this one without threads, instead using select(). However, in order to do it properly, you'll need three buffers to read into. The reason is that with a socket connection, it's entirely possible that you'll get fewer than 20 bytes from one read -- you do not want to shut out the other connections while you wait for the remaining bytes from a connection that have given you fewer than 20 bytes.

I'll give you both versions. First, the threaded version:


#include 
#include 
#include "socketfun.h"

typedef struct {
  char *host;
  int port;
  int *lineno;
  pthread_mutex_t *lock;
} Targ;

void *thread(void *arg)
{
  Targ *targ;
  char buffer[61];
  int fd;
  int i, j;

  targ = (Targ *) arg;
  
  fd = request_connection(targ->host, targ->port);

  while(1) {
    i = 0;
    while (i < 20) {
      j = read(fd, buffer+i, 20-i);
      if (j == 0) exit(0);
      i += j;
    }
    buffer[20] = '\0';
    pthread_mutex_lock(targ->lock);
    (*targ->lineno)++;
    printf("%5d: %s %s", *targ->lineno, targ->host, buffer);
    pthread_mutex_unlock(targ->lock);
  }
  return NULL;
} 

main()
{
  pthread_t tids[3];
  Targ targs[3];
  int i;
  int lineno;
  pthread_mutex_t lock;

  lineno = 0;

  pthread_mutex_init(&lock, NULL);

  for (i = 0; i < 3; i++) {
    targs[i].lineno = &lineno;
    targs[i].lock = &lock;
    targs[i].port = 9201;
  }
  targs[0].host = "cetus4b.cs.utk.edu";
  targs[1].host = "o.cs.ucsb.edu";
  targs[2].host = "liz.cs.harvard.edu";

  for (i = 0; i < 3; i ++ ) {
    pthread_create(tids+i, NULL, thread, (void *) (&targs[i]));
  }
  pthread_exit(NULL);
}
And now the non-threaded version:
#include < stdio.h >
#include < sys/time.h >
#include < sys/types.h >
#include < unistd.h >
#include "socketfun.h"

main()
{
  int fds[3];
  char *strings[3];
  char buffers[3][21];
  int indices[3];
  int lineno;
  fd_set readset;
  int maxfd;

  lineno = 0;
  maxfd = 0;
  strings[0] = "cetus4b.cs.utk.edu";
  strings[1] = "o.cs.ucsb.edu";
  strings[2] = "liz.cs.harvard.edu";

  for (i = 0; i < 3; i++) {
    fds[i] = request_connection(strings[i], 9200);
    if (fds[i] > maxfd) maxfd = fds[i];
    indices[i] = 0;
  }

  while(1) {
    FD_ZERO(&readset);
    for (i = 0; i < 3; i++) FD_SET(fds[i], &readset);

    if (select(maxfd+1, &readset, NULL, NULL, NULL) <= 0) exit(1);
    for (i = 0; i < 3; i++) {
      if (FD_ISSET(i, &readset)) {
        j = read(fds[i], buffers[i]+indices[i], 20-indices[i]);
        if (j == 0) exit(0);
        indices[i] += j;
        if (indices[i] == 20) {
          buffers[i][20] = '\0';
          lineno++;
          printf("%5d %s %s\n", lineno, strings[i], buffers[i]);
          indices[i] = 0;
        }
      }
    }
  }
}

  
}

Grading

The grading of this one is a pain, but it consists of three parts, each worth 4 points.