[ Team LiB ] Previous Section Next Section

26.9 Web Client and Simultaneous Connections (Continued)

We now recode our Web client from Section 26.6, removing the call to the Solaris thr_join function and replacing it with a call to pthread_join. As discussed in that section, we now must specify exactly which thread we are waiting for. To do this we will use a condition variable, as described in Section 26.8

The only change to the globals (Figure 26.13) is to add one new flag and the condition variable.


     #define   F_JOINED        8   /* main has pthread_join'ed */

     int              ndone;       /* number of terminated threads */
     pthread_mutex_t  ndone_mutex = PTHREAD_MUTEX_INITIALIZER;
     pthread_cond_t   ndone_cond  = PTHREAD_COND_INITIALIZER;

The only change to the do_get_read function (Figure 26.15) is to increment ndone and signal the main loop before the thread terminates.


          printf("end-of-file on %s\n", fptr->f_name);
          Close(fd);

          Pthread_mutex_lock(&ndone_mutex);
          fptr->f_flags = F_DONE;     /* clears F_READING */
          ndone++;
          Pthread_cond_signal(&ndone_cond);
          Pthread_mutex_unlock(&ndone_mutex);

          return(fptr);       /* terminate thread */
  }

Most changes are in the main loop, Figure 26.14, the new version of which we show in Figure 26.19.

Figure 26.19 Main processing loop of main function.

threads/web03.c

43     while (nlefttoread > 0) {
44         while (nconn < maxnconn && nlefttoconn > 0) {
45                 /* find a file to read */
46             for (i = 0; i < nfiles; i++)
47                 if (file[i].f_flags == 0)
48                     break;
49             if (i == nfiles)
50                 err_quit("nlefttoconn = %d but nothing found", nlefttoconn);

51             file[i].f_flags = F_CONNECTING;
52             Pthread_create(&tid, NULL, &do_get_read, &file[i]);
53             file[i].f_tid = tid;
54             nconn++;
55             nlefttoconn--;
56          }

57              /* Wait for thread to terminate */
58          Pthread_mutex_lock(&ndone_mutex);
59          while (ndone == 0)
60              Pthread_cond_wait(&ndone_cond, &ndone_mutex);

61          for (i = 0; i < nfiles; i++) {
62              if (file[i].f_flags & F_DONE) {
63                  Pthread_join(file[i].f_tid, (void **) &fptr);

64                  if (&file[i] != fptr)
65                      err_quit("file[i]!= fptr");
66                  fptr->f_flags = F_JOINED;  /* clears F_DONE */
67                  ndone--;
68                  nconn--;
69                  nlefttoread--;
70                  printf("thread %d for %s done\n", fptr->f_tid, fptr->f_name);
71               }
72          }
73          Pthread_mutex_unlock(&ndone_mutex);
74     }

75     exit(0);
76 }

If possible, create another thread

44–56 This code has not changed.

Wait for thread to terminate

57–60 To wait for one of the threads to terminate, we wait for ndone to be nonzero. As discussed in Section 26.8, the test must be done while the mutex is locked. The sleep is performed by pthread_cond_wait.

Handle terminated thread

61–73 When a thread has terminated, we go through all the file structures to find the appropriate thread, call pthread_join, and then set the new F_JOINED flag.

Figure 16.20 shows the timing for this version, along with the timing of the version using nonblocking connects.

    [ Team LiB ] Previous Section Next Section