[ Team LiB ] Previous Section Next Section

30.8 TCP Preforked Server, Thread Locking Around accept

As we mentioned, there are various ways to implement locking between processes. The POSIX file locking in the previous section is portable to all POSIX-compliant systems, but it involves filesystem operations, which can take time. In this section, we will use thread locking, taking advantage of the fact that this can be used not only for locking between the threads within a given process, but also for locking between different processes.

Our main function remains the same as in the previous section, as do our child_make and child_main functions. The only thing that changes is our three locking functions. To use thread locking between different processes requires that: (i) the mutex variable must be stored in memory that is shared between all the processes; and (ii) the thread library must be told that the mutex is shared among different processes.

Also, the thread library must support the PTHREAD_PROCESS_SHARED attribute.

There are various ways to share memory between different processes, as we described in the second volume of this series. In our example, we will use the mmap function with the /dev/zero device, which works under Solaris and other SVR4 kernels. Figure 30.18 shows our my_lock_init function.

Figure 30.18 my_lock_init function using Pthread locking between processes.

server/lock_pthread.c

 1 #include    "unpthread.h"
 2 #include    <sys/mman.h>

 3 static pthread_mutex_t *mptr;    /* actual mutex will be in shared memory */

 4 void
 5 my_lock_init(char *pathname)
 6 {
 7     int     fd;
 8     pthread_mutexattr_t mattr;

 9     fd = Open("/dev/zero", O_RDWR, 0);

10     mptr = Mmap(0, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE,
11                 MAP_SHARED, fd, 0);
12     Close(fd);

13     Pthread_mutexattr_init(&mattr);
14     Pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
15     Pthread_mutex_init(mptr, &mattr);
16 }

9–12 We open/dev/zero and then call mmap. The number of bytes that are mapped is equal to the size of a pthread_mutex_t variable. The descriptor is then closed, which is fine, because the memory mapped to /dev/zero will remain mapped.

13–15 In our previous Pthread mutex examples, we initialized the global or static mutex variable using the constant PTHREAD_MUTEX_INITIALIZER (e.g., Figure 26.18). But with a mutex in shared memory, we must call some Pthread library functions to tell the library that the mutex is in shared memory and that it will be used for locking between different processes. We first initialize a pthread_mutexattr_t structure with the default attributes for a mutex and then set the PTHREAD_PROCESS_SHARED attribute. (The default for this attribute is PTHREAD_PROCESS_PRIVATE, allowing use only within a single process.) pthread_mutex_init then initializes the mutex with these attributes.

Figure 30.19 shows our my_lock_wait and my_lock_release functions. Each is now just a call to a Pthread function to lock or unlock the mutex.

Comparing rows 3 and 4 in Figure 30.1 for the Solaris server shows that thread mutex locking is faster than file locking.

    [ Team LiB ] Previous Section Next Section