命名信号量

命名信号量:这种信号量拥有一个名字。通过使用相同的名字调用sem_open(),不相关的进程能够访问同一个信号量

打开一个命名信号量

sem_t *sem_open(const char *name, int oflag, ...
                /* mode_t mode, unsigned int value*/);
  • 参数:
    • name: 信号量的名字,斜线开头,如 /demo_sem

    • oflag: 控制信号量的打开方式

      • O_CREAT: 如果信号量不存在,则创建一个新信号量

      • O_EXCL: 配合 O_CREAT 一起使用时,确保调用进程是创建者

        默认是可读写的

    • mode: 参数指定信号量的权限

    • value: 该参数指定信号量的初始值

      mode和value两个参数只有在指定O_CREAT时才使用

  • 返回值
    成功返回信号量,失败返回 SEM_FAILED

关闭一个命名信号量

int sem_close(sem_t *sem);

当一个进程打开一个命名信号量时,系统会记录进程与信号量之间的关联关系。sem_close()函数会终止这种关联关系(即关闭信号量),释放系统为该进程关联该信号量之上的所有资源,并递减引用该信号量的进程数

关闭信号量,不是删除这个信号量,就像是,关闭文件描述符,不会删除文件一样

删除一个命名信号量

int sem_unlink(const char *name);

sem_unlink()函数删除通过 name 标识的信号量并将信号量标记成一旦所有进程都使用完这个信号量时就销毁该信号量(这可能立即发生,前提是所有打开过该信号量的进程都已经关闭了这个信号量)。

修改信号量的值

等待一个信号量

sem_wait()函数会递减(减小1)sem引用的信号量的值

int sem_wait(sem_t *sem); 

若是信号量的值大于0,则会立即减1,等于0,则会一直阻塞,直到信号量增加

表示 进程正在等待一个资源

发布一个信号量

sem_post()函数递增(增加1)sem引用的信号量的值。

int sem_post(sem_t *sem);

若信号量的值等于0,并且其他进程正在等待这个信号量,那么当发布信号量后,等待的进程会被唤醒,如果有多个进程等待,则不保证唤醒顺序

表示 进程释放了一个资源

获取信号量的值

sem_getvalue()函数将 sem 引用的信号量的当前值通过sval指向的int变量返回

int sem_getvalue(sem_t *sem, int *sval); // 获取信号量的值可能在获取后又被修改了

如果一个或多个进程(或线程)当前正在阻塞以等待递减信号量值,那么sval 中的返回值将取决于实现。SUSv3允许两种做法:0或一个绝对值等于在sem_wait()中阻的等待者数目的负数。Linux和其他一些实现采用了第一种行为,而另一些实现则采用了后一种行为。

未命名信号量(基于内存的信号量)

未命名信号量:这种信号量没有名字,相反,它位于内存中一个预先商定的位置处。未命名信号量可以在进程之间或一组线程之间共享。当在进程之间共享时,信号量必须位于一个共享内存区域中(System V、POSIX或mmap())。当在线程之间共享时,信号量可以位于被这些线程共享的一块内存区域中(如在堆上或在一个全局变量中)

初始化一个未命名信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);

参数 pshared 表示该信号量是在进程间共享还是线程间共享

  • pshared = 0 表示在 线程间共享,则信号量分配在全局变量或者堆上等地址处,在进程终止后销毁
  • pshared = 1 表示在 进程间共享,则信号量分配在一片共享内存区域(共享内存对象或者共享内存映射),fork调用会使子进程继承父进程的共享内存区域,这样两者就能通过信号量进行同步了

销毁一个未命名信号量

int sem_destroy(sem_t *sem);

sem_destroy()函数将销毁信号量 sem,其中 sem 必须是一个之前使sem_init()进行初始化的未命名信号量。只有在不存在进程或线程在等待一个信号量时才能够安全销毁这个信号量。

需要注意的是,信号量销毁的时机,线程间共享,则要在进程终止前销毁,进程间共享,则要在没有进程引用信号量以及删除共享内存映射前销毁

 posted on 2024-11-02 17:42  Dylaris  阅读(62)  评论(0)    收藏  举报