20 sleep (1);
21 }
22 }
23 status = pthread_mutex_lock (&client_mutex);
24 if (status != 0)
25 err_abort (status, 'Lock client mutex');
26 client_threads--;
27 if (client_threads <= 0) {
28 status = pthread_cond_signal (&clients_done);
29 if (status != 0)
30 err_abort (status, 'Signal clients done');
31 }
32 status = pthread_mutex_unlock (&client_mutex);
33 if (status != 0)
34 err_abort (status, 'Unlock client mutex');
35 return NULL;
36 }
¦ server.c part 4 client_routine
Part 5 shows the main program for server.c. It creates a set ofclient threads to utilize the tty server, and waits for them.
7-15 On a Solaris system, set the concurrency level to the number of client threads by calling thr_setconcurrency. Because all the client threads will spend some of their time blocked on condition variables, we don't really need to increase the concurrency level for this program — however, it will provide less predictable execution behavior.
20-26 Create the client threads.
27-35 This construct is much like pthread_join, except that it completes only when all of the client threads have terminated. As I have said elsewhere, pthread_join is nothing magical, and there is no reason to use it to detect thread termination unless it does exactly what you want. Joining multiple threads in a loop with pthread_join is rarely exactly what you want, and a 'multiple join' like that shown here is easy to construct.
¦ server.c part 5 main
1 int main (int argc, char *argv[])
2 {
3 pthread_t thread;
4 int count;
5 int status; 6
7 #ifdef sun
8 /*
9 * On Solaris 2.5, threads are not timesliced. To ensure
10 * that our threads can run concurrently, we need to
11 * increase the concurrency level to CLIENT_THREADS.
12 */
13 DPRINTF (('Setting concurrency level to %d
', CLIENT_THREADS));
14 thr_setconcurrency (CLIENT_THREADS);
15 #endif
16
17 /*
18 * Create CLIENT_THREADS clients.
19 */
20 client_threads = CLIENT_THREADS;
21 for (count = 0; count < client_threads; count++) {
22 status = pthread_create (&thread, NULL,
23 client_routine, (void*)count);
24 if (status != 0)
25 err_abort (status, 'Create client thread');
26 }
27 status = pthread_mutex_lock (&client_mutex);
28 if (status != 0)
29 err_abort (status, 'Lock client mutex');
30 while (client_threads > 0) {
31 status = pthread_cond_wait (&clients_done, &client_mutex);
32 if (status != 0)
33 err_abort (status, 'Wait for clients to finish');
34 }
35 status = pthread_mutex_unlock (&client_mutex);
36 if (status != 0)
37 err_abort (status, 'Unlock client mutex');
38 printf ('All clients done
');
39 tty_server_request (REQ_QUIT, 1, NULL, NULL);
40 return 0;
41 }
5 Advanced threaded programming
'Take same more tea,' the March Hare said to Alice, very earnestly.
'I've had nothing yet,'Alice replied in an offended tone:
'so I ca'n't take more.'
'You mean you ca'n't take less,'said the Hatter:
'it's very easy to take more than nothing.'
Section 5.1 describes a facility to manage initialization of data, particularly within a library, in a multithreaded environment.
Section 5.2 describes 'attributes objects,' a way to control various characteristics ofyour threads, mutexes, and condition variables when you create them.
Section 5.3 describes cancellation, a way to ask your threads to 'go away' when you don't need them to continue.
Section 5.4 describes thread-specific data, a sort ofdatabase mechanism that allows a library to associate data with individual threads that it encounters and to retrieve that data later.
Section 5.5 describes the Pthreads facilities for realtime scheduling, to help your program interact with the cold, cruel world in a predictable way.