Pthread - Mutexでプロセス間排他制御を行う

使用するシステムコールAPI

Mutex関連

#include <pthread.h>

int pthread_mutex_init(
        pthread_mutex_t *mutex, 
        const pthread_mutexattr_t *attr);

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

int pthread_mutex_destroy(pthread_mutex_t *mutex);


Mutex属性関連

#include <pthread.h>

int pthread_mutexattr_init(pthread_mutexattr_t *attr);

int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);

int pthread_mutexattr_setpshared(
        pthread_mutexattr_t *attr,
        int pshared);



メモリマップドファイル関連

#include <sys/mman.h>

void *mmap(void *start, size_t length, 
        int prot, int flags, int fd, off_t offset);

int munmap(void *start, size_t length);



  • ファイルから数字を読み込み、カウントアップして同じファイルに書き戻すプロセスを複数生成し、互いのプロセス間で排他制御を行う。その際に、Mutexとメモリマップドファイルを用いる
  • #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    
    #define FILENAME "counter"
    
    static pthread_mutex_t *mptr;
    
    void
    my_lock_init()
    {
        int fd;
        pthread_mutexattr_t mattr;
        fd = open("/dev/zero", O_RDWR, 0);
        mptr = (pthread_mutex_t*)mmap(0, 
                             sizeof(pthread_mutex_t),  
                             PROT_READ|PROT_WRITE,
                             MAP_SHARED, 
                             fd, 
                             0);
        close(fd);
        
        pthread_mutexattr_init(&mattr);
        pthread_mutexattr_setpshared(&mattr, 
                                    PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(mptr, &mattr);
    }
    
    void
    my_lock_wait()
    {
        pthread_mutex_lock(mptr);
    }
    
    void
    my_lock_release()
    {
        pthread_mutex_unlock(mptr);
    }
    
    void 
    my_lock_destroy()
    {
        munmap(0, sizeof(pthread_mutex_t));
        pthread_mutex_destroy(mptr);
    }
    
    void 
    print_counter()
    {
        int counter;
        char buff[16];
        FILE *fp;
      
        my_lock_wait();
        
        ///////////////////////////////////////
        //Critical Region
        if ( (fp = fopen(FILENAME, "r")) != NULL ) {
            fgets(buff, sizeof(buff), fp);
            fclose(fp);
            counter = atoi(buff);
            counter++;
        }
        
        printf("%d\n", counter);
            
        if ( (fp = fopen(FILENAME, "w")) != NULL ) {
            fprintf(fp, "%d", counter);
            fclose(fp);
        }
        //Critical Region
        ///////////////////////////////////////
        
        my_lock_release();
    }
    
    void init_counter_file()
    {
        FILE *fp;
        fp = fopen(FILENAME, "w");
        fprintf(fp, "0");
        fclose(fp);
    }
    
    int
    main()
    {
        int i;
        pid_t pids[1000];
        int n;    
        
        init_counter_file();
        my_lock_init();
        n = sizeof(pids)/sizeof(pids[0]);
        
        for (i = 0; i < n; i++) {
            if ( (pids[i] = fork() ) == 0) {
                print_counter();
                exit(0);
            }
        }
        
        for (i = 0; i < n; i++) {
            waitpid(pids[i], NULL, 0);
            printf("pid %u is ended\n", pids[i]);
        }
        
        my_lock_destroy();
        
        puts("Exit");
        
        return 0;
    }
    

    参考 UNIXネットワークプログラミング Vol.1 スティーヴンズ