POSIX信号量的使用

1. 概述

信号量分为有名信号量(named semaphore),无名信号量(unnamed semaphore)。

(这里说的信号量主要是指semaphore.h中的信号量)

  1. 有名信号量由sem_open打开,无名信号量由sem_init打开.
  2. 有名信号量通过sem_unlink删除, 无名信号量通过sem_destroy删除信号量
  3. 有名信号量由内核持续,正是因此多个进程间才能利用它;无名信号量一般是线程之间使用,也可以搭配共享内存在多进程之间使用。

2. 函数原型

#include <semaphore.h>

// 有名信号量的操作
sem_t *sem_open(const char *, int, ...);
int    sem_unlink(const char *);
int    sem_close(sem_t *);

// 无名信号量的操作
int    sem_init(sem_t *, int, unsigned int);
int    sem_destroy(sem_t *);

// 获取信号量值
int    sem_getvalue(sem_t *, int *);

// 发出信号,即释放拥有权
int    sem_post(sem_t *);
// 等待信号,即获取拥有权
int    sem_trywait(sem_t *);
int    sem_wait(sem_t *);

3. 用信号量解生产者-消费者问题

#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define NUMBER  50000
#define CHILD   5
#define BUFSIZE 10

// critical resource
int fd;

// semaphore
sem_t* empty;
sem_t* full;
sem_t* mutex;

void comsumer() {
    int buf_out = 0;
    int data = 0;
    int cnt = 0;
    for (int k = 0; k < NUMBER / CHILD; k++) {
        sem_wait(full);
        sem_wait(mutex);
        
        // fetch buf_out
        lseek(fd, BUFSIZE * sizeof(int), SEEK_SET);
        read(fd, (char*)&buf_out, sizeof(int));

        cnt++;
        lseek(fd, sizeof(int) * buf_out, SEEK_SET);
        read(fd, (char*)&data, sizeof(int));
        printf("%d comsume %d %d\n", getpid(), data, cnt);
        fflush(stdout);
        
        // write back
        buf_out = (buf_out + 1) % BUFSIZE;
        lseek(fd, BUFSIZE * sizeof(int), SEEK_SET);
        write(fd, (char *)&buf_out, sizeof(int));

        sem_post(mutex);
        sem_post(empty);
    }
    printf("%d total consume %d\n", getpid(), cnt);
}

void producer() {
    int buf_in = 0;
    for (int i = 0 ; i < NUMBER; i++) {
        sem_wait(empty);
        sem_wait(mutex);
        
        lseek(fd, buf_in * sizeof(int), SEEK_SET);
        write(fd, (char*)&i, sizeof(int));
        buf_in = (buf_in + 1) % BUFSIZE;
        printf("produce %d\n", i);
        fflush(stdout);

        sem_post(mutex);
        sem_post(full);
    }
}


int main() {
    mutex = sem_open("mutex", O_CREAT | O_EXCL, 0644, 1); 
    full = sem_open("full", O_CREAT | O_EXCL, 0644, 0); 
    empty = sem_open("empty", O_CREAT | O_EXCL, 0644, BUFSIZE); 
    
    int out_index = 0;
    fd = open("buffer.dat", O_CREAT | O_RDWR | O_TRUNC, 0666);
    lseek(fd, BUFSIZE * sizeof(int), SEEK_SET);
    write(fd, (char *)&(out_index), sizeof(int));

    pid_t p;
    // create producer
    if ((p = fork()) == 0) {
        producer();
        return 0;
    } else if (p < 0){
        printf("Fail to fork!\n");
        return -1;
    }

    // create comsumer
    for (int j = 0; j < CHILD ; j++)
    {
        if ((p = fork()) == 0) {
            comsumer();
            return 0;
        } else if (p < 0) {
            printf("Fail to fork!\n");
            return -1;
        }
    }
    int cnt = 0;
    printf("wait children!\n");
    pid_t pid;
    while (pid = waitpid(-1, NULL, 0)) {
        if (errno == ECHILD) {
            break;
        }
        cnt ++;
        printf("pid: %d end | sum: %d\n", pid, cnt);
    }

    sem_unlink("empty");
    sem_unlink("full");
    sem_unlink("mutex");

    return 0;
}

编译命令:

g++ pcc.c -o test -lpthread

参考资料

[1] 信号量

[2] semaphore.h

posted @ 2022-04-18 20:55  zju_cxl  阅读(72)  评论(0编辑  收藏  举报