Linux多进程通信(2)——POSIX信号量使用例程

1.POSIX信号量

1)POSIX信号量和System V信号量区别
常用的是POSIX信号量,使用起来更加方便,而POSIX信号量分为有名信号量和无名信号量

POSIX信号量是多线程多进程安全的,而System V标准的信号量并不是,Posix通过sem_open单一的调用就完成了信号量的创建、初始化和权限的设置,而System V要两步。

POSIX无名信号量,非多进程共享时,相当于存放在进程的全局变量,进程结束则内存销毁,而若是有名信号量,则存在共享内存中,只要共享内存区存在,则信号灯就一直存在,这也是使用时经常发现sem_open调用失败的原因

POSIX信号量,用ls /dev/shm能看到,而System V信号量,则是使用ipcs -s查看。

2)无名信号量和有名信号量
有名信号量:可以在多进程间使用,多进程通过名字来打开同一个信号量,使用范围更广
无名信号量:一般在多线程使用,因为没有名字,所以没法在多进程中打开同一个信号量
image.png

2.信号量创建

1)有名信号量

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);

oflag:可取O_CREAT和O_EXCL,取O_CREAT时,表示要创建信号量,用O_CREAT时文件存在,就返回错误信息,一般会使用O_CREAT和O_EXCL一起,信号量不存在则创建,存在则报错
mode:读写权限,如0777
value:信号量初始值

2)无名信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);

sem:信号量指针
pshared:0,用于线程间(全局变量),非0用于进程间(共享内存)
value:信号量初始值

3.信号量销毁

1)有名信号量

#include <semaphore.h>
int sem_close(sem_t *sem); /// 信号量关闭
int sem_unlink(const char *name); ///信号量删除

信号量关闭并不等于删除。
进程会记录进程和信号的关系,调用sem_close时,会终止这种关联关系,信号量的进程数的引用计数减1,但即使通过调用sem_close将信号量计数到0,也不会删除
而调用sem_unlink时,若引用计数不为0,则需要当所有打开该信号量的进程,都将信号量关闭,才会真正进行删除操作

2)无名信号量

#include <semaphore.h>
int sem_destroy(sem_t *sem);

调用sem_destroy时,只有当所有进程都不再等待这个信号量时需要用户确保!),才能安全销毁。

4.等待信号量

#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

若信号量计数大于0,则成功拿到信号量,信号量计数-1,可以访问共享资源,若信号量计数小于等于0,则无法拿到信号量,执行的进程会放到PCB等待队列
sem_wait:阻塞等待信号量,拿到信号量再返回
sem_trywait:非阻塞尝试拿信号量,不阻塞。成功则返回0,失败返回EAGAIN
sem_timedwait:设定最大超时的阻塞式等待信号量,若不超时返回0,超过abs_timeout的等待时间,则返回-1, 并置errno为ETIMEOUT。

使用sem_timedwait的陷阱:

4.发布信号量

#include <semaphore.h>
int sem_post(sem_t *sem);

表示共享资源使用完毕,归还共享资源,使信号量计数+1
如果发布信号量之前, 信号量的值是0, 并且已经有进程或线程正等待在信号量上, 此时会有一个进程被唤醒, 被唤醒的进程会继续sem_wait函数的减1操作。如果有多个进程正等待在信号量上, 那么将无法确认哪个进程会被唤醒。如果发布信号量时,并没有进程在等待,则内核会维护这个计数,直到有人来取走信号量。
函数调用成功时, 返回0; 失败时, 返回-1, 并置errno。 当参数sem并不指向合法的信号量时, 置errno为EINVAL; 当信号量的值超过上限时, 置errno为EOVERFLOW

5.例程

1)server.c

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>

#define SEM_NAME "sem_test"
int main(int argc, char **argv)
{
    int iRet = 0;
    int iSemCnt = 0;
    sem_t *pSem = sem_open(SEM_NAME, O_CREAT|O_EXCL, 0777, 1);
    if (!pSem)
    {
        printf("server sem open failed\n");
        return -1;
    }
    sem_getvalue(pSem, &iSemCnt);
    printf("server begin for wait sem:%p, sem cnt:%d\n", pSem, iSemCnt);
    sem_wait(pSem);
    sem_getvalue(pSem, &iSemCnt);
    printf("server wait sem:%p success, sem cnt:%d\n", pSem, iSemCnt);

    sleep(5);
    sem_post(pSem);
    sem_getvalue(pSem, &iSemCnt);
    printf("server send sem:%p success, sem cnt:%d\n", pSem, iSemCnt);

    sleep(5);
    sem_close(pSem);
    sem_unlink(SEM_NAME);

    return 0;
}

2)client.c

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>

#define SEM_NAME "sem_test"
int main(int argc, char **argv)
{
    int iRet = 0;
    int iSemCnt = 0;
    sem_t *pSem = sem_open(SEM_NAME, O_RDWR);
    if (!pSem)
    {
        printf("server sem open failed\n");
        return -1;
    }
    sem_getvalue(pSem, &iSemCnt);
    printf("client begin for wait sem:%p, sem cnt:%d\n", pSem, iSemCnt);
    sem_wait(pSem);
    sem_getvalue(pSem, &iSemCnt);
    printf("client wait sem:%p success, sem cnt:%d\n", pSem, iSemCnt);

    sleep(5);

    sem_close(pSem);
    printf("client close sem: success\n", pSem);

    return 0;
}

其中server在open打开信号量后,设置计数为1,并进行wait操作,之后延时5S发送信号量,这个信号量成功被client给拿到,打印等待成功。
image.png

相关推荐

  1. Linux-线同步(条件变POSIX信号

    2024-04-02 05:18:04       24 阅读
  2. linux c进程通信之共享内存和信号

    2024-04-02 05:18:04       39 阅读
  3. Linux】学习记录_15_POSIX信号

    2024-04-02 05:18:04       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-02 05:18:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-02 05:18:04       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-02 05:18:04       87 阅读
  4. Python语言-面向对象

    2024-04-02 05:18:04       96 阅读

热门阅读

  1. UltraScale系列底层结构(1)——引言

    2024-04-02 05:18:04       36 阅读
  2. 技术与安全的交织

    2024-04-02 05:18:04       39 阅读
  3. spring AOP和AspectJ AOP的区别

    2024-04-02 05:18:04       34 阅读
  4. 零基础10 天入门 Web3之第2天

    2024-04-02 05:18:04       36 阅读
  5. HarmonyOS 应用开发之XML生成、解析与转换

    2024-04-02 05:18:04       27 阅读
  6. 1.创建型模式--单例模式

    2024-04-02 05:18:04       37 阅读
  7. DHCP(动态主机配置协议)

    2024-04-02 05:18:04       43 阅读
  8. 《1w实盘and大盘基金预测 day14》

    2024-04-02 05:18:04       35 阅读
  9. DQL语言(数据库检索select)1

    2024-04-02 05:18:04       29 阅读