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鈥?6
This code has not changed.
Wait for thread to terminate
57鈥?0
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鈥?3
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.
|