进程间通信之Posix 信号量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/AlbertoNo1/article/details/73865111

概述

    信号量(semaphore)是一种用于提供不同进程间或者一个给定进程的不同线程间同步手段的原语。

    本文讨论:

    1.Posix 有名信号量:使用Posix IPC 名字标识,可用于进程或线程间的同步。

    2.Posix 基于内存的信号量:存放在共享内存区中,可用于进程或线程间的同步。


    我们暂时只考虑不同进程间的同步。首先考虑二值信号量(binary semaphore):其值或为0或为1的信号量。




    Posix 信号量不必在内核中维护。另外,Posix 信号量是由可能与文件系统中的路径名对应的名字来标识的,但是并不要求它们真正存放在文件系统内的某个文件中。


    由上图可看出,进程可以在某个信号量上执行三种操作:

    1.创建一个信号量。要求调用者指定初始值,对于二值信号量来说,它通常是1,但也可以是0。

    2.等待一个信号量。该操作会测试这个信号量的值,如果其值小于或等于0,那就等待(阻塞),一旦其值变为大于0就将它减1。

    3.挂出一个信号量。该操作将信号量的值加1,如果有一些进程阻塞着等待该信号量的值变为大于0,其中一个进程就可能被唤醒。


    有名信号量和基于内存的信号量使用函数对比:



函数说明

   sem_open、sem_close和sem_unlink函数

    1.函数sem_open创建一个新的有名信号量或打开一个已存在的有名信号量。有名信号量总是既可用于线程间的同步,又可用于进程间的同步。

sem_t *sem_open(const char *name, int oflag, ... /*mode_t mode, unsigned int value*/);

        返回:若成功则为指向信号量的指针,若出错则为SEM_FAILED。

        name 参数规则:1.必须符合已有的路径名规则(最多有PATH_MAX个字符构成,包括结尾的空字符); 2.名字必须已一个斜杠符开头,并且不能函数任何其他斜杠符;

        oflag 参数:可以是0、O_CREAT(若不存在则创建)或OCREAT | O_EXCL(排他性创建)。如果指定了O_CREAT标志,那么第三个和第四个参数是需要的。

        mode 参数:指定权限位 。

        value 参数:指定信号量的初始值。二值信号量的初始值通常为1,计数信号量的初始值则往往大于1。

        备注:oflag 参数中还可以指定 O_RDONLY  O_WRONLY 或 O_RDWR标志,但通常调用sem_open 默认携带O_RDWR标志。


    2.函数sem_close关闭打开的一个有名信号量。

int sem_close(sem_t *sem);

        返回:若成功则为0,若出错则为-1。

        一个进程终止时,内核还对其上仍然打开着的所有有名信号量自动执行这样的信号量关闭操作。关闭一个信号量并没有将它从系统中删除,因为Posix信号量是随内核持续的:即使当前没有进程打开着某个信号量,它的值仍然保持。

        有名信号量使用sem_unlink函数从系统中删除:

int sem_unlink(const char *name);

        返回:若成功则为0,若出错则为-1。


    sem_wait和sem_trywait函数   

int sem_wait(sem_t *sem);

int sem_trywait(sem_t *sem);

        返回:若成功则为0,若出错则为-1。

        sem_wait函数测试所指定的信号量的值,如果该值大于0,那就将它减1并立即返回。如果该值等于0,调用线程就被投入到睡眠中,直到该值变为大于0,这时再将它减1,函数随后返回。

        sem_wait和sem_trywait的差别是:当所指定的信号量的值已经是0时,后者并不将调用线程投入睡眠。相反,它返回一个EAGAIN错误。


    sem_post和sem_getvalue函数

int sem_post(sem_t *sem);

int sem_getvalue(sem_t *sem, int *valp);

        返回:若成功则为0,若出错则为-1。

        当一个线程使用完某个信号量时,它应该调用sem_post。本函数把所指定的信号量的值加1,然后唤醒正在等待该信号量值变为正数的任意线程。

        sem_getvalue在有valp指向的整数中返回所指定信号量的当前值。如果该信号量当前已经上锁,那么返回或为0,或为某个负数,其绝对值就是等待该信号量解锁的线程数。


    互斥锁、条件变量和信号量之间的差别:

    首先,互斥锁必须总是由给它上锁的线程解锁,信号量没有这种限制。其次,既然每个信号量有一个与之关联的值,它由挂出操作加1,由等待操作减1,那么任何线程都可以挂出一个信号量,即使当时没有线程等待该信号量值变为正数也没有关系。然而,如果某个线程调用了pthread_cond_signal,不过当时没有任何线程阻塞在pthread_cond_wait调用中,那么发往相应条件变量的信号将丢失。最后,在各种各样的同步技巧(互斥锁、条件变量、读写锁、信号量)中,能够从信号处理程序中安全调用的唯一函数就是sem_post。



例子

待补充...




猜你喜欢

转载自blog.csdn.net/AlbertoNo1/article/details/73865111