named semaphore,进程同步

-- TOC --

进程间的同步,可以使用命名信号量(named semaphore)。

$ man 7 sem_overview

named semaphore在创建后,位于/dev/shm路径下。

fork后的子进程,继承了semaphore,但是不会继承对semaphore的操作。

下面是测试代码,多进程同时读写一个硬盘文件:

$ cat test_sem.c
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/wait.h>


#define _PEXIT \
    do {\
        char ebuf[64] = {0};\
        sprintf(ebuf, "%s: %d", __FILE__, __LINE__);\
        perror(ebuf);\
        exit(errno);\
    }while(0)


void increment1(sem_t *sem, char *file_name) {
    sem_wait(sem);

    int a;
    FILE *fp = fopen(file_name, "r");
    fscanf(fp, "%d", &a);
    fclose(fp);

    fp = fopen(file_name, "w");
    fprintf(fp, "%d", a+1);
    fclose(fp);

    sem_post(sem);
}


int main(int argc, char **argv) {
    /* child process number */
    int pnum;
    if (argc == 2)
        pnum = atoi(argv[1]);
    else
        pnum = 4;  /* default child process number */

    /* create a file which contain a number zero */
    char *file_name = "number.txt";
    FILE *fp = fopen(file_name, "w");
    if (fp == NULL)
        _PEXIT;
    fprintf(fp, "%d", 0);
    fclose(fp);

    /* create a semaphore with value 1 */
    char *sem_name = "/sem_test";
    sem_t *sem;
    sem = sem_open(sem_name, O_CREAT|O_RDWR, 0666, 1);
    if (sem == SEM_FAILED)
        _PEXIT;

    /* fork child */
    int cnum = pnum;
    pid_t cpid;
    while (cnum--) {
        if ((cpid=fork()) == 0) {
            /* add 2 */
            increment1(sem, file_name);
            increment1(sem, file_name);
            exit(0);
        } else if (cpid == -1)
            _PEXIT;
    }

    /* wait all */
    int wnum = pnum;
    while (wnum--)
        wait(NULL);

    /* read out final number */
    int a;
    fp = fopen(file_name, "r");
    fscanf(fp, "%d", &a);
    fclose(fp);
    printf("%d\n", a);

    /* close and remove semaphore */
    sem_close(sem);
    sem_unlink(sem_name);

    /* delete file */
    unlink(file_name);

    return 0;
}

文件中只有一个数字,进程每次获取到semaphore之后,对此数字进行+1操作。默认开启4个子进程,每个子进程执行两次+1。

运行效果如下:

$ gcc -Wall -Wextra test_sem.c -o test_sem
$ ./test_sem 
8
$ ./test_sem 8
16
$ ./test_sem 80
160
$ ./test_sem 800
1600

代码测试结果符合预期,多个进程确实同步了。

进程间也可以使用匿名信号量,需要将匿名信号量放入进程间的共享内存中,具体可参考:man 3 sem_init

本文链接:https://cs.pynote.net/sf/linux/prog/202208011/

-- EOF --

-- MORE --