Linux进程间通信机制:信号量

        注意请不要把它与信号混淆起来, 信号与信号量是不同的两种事物。 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题, 我们需要一种方法, 它可以通过生成并使用令牌来授权, 在任一时刻只能有一个执行线程访问代码的临界区域。 临界区域是指执行数据更新的代码需要独占式地执行。 而信号量就可以提供这样的一种访问机制, 让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程对共享资源的访问的。
        信号量是一个特殊的变量, 程序对其访问都是原子操作, 且只允许对它进行等待(即 P(信号变量))和发送(即 V(信号变量))信息操作。 最简单的信号量是只能取 0 和 1 的变量, 这也是信号量最常见的一种形式,叫做二进制信号量。 而可以取多个正整数的信号量被称为通用信号量。 这里主要讨论二进制信号量。
        由于信号量只能进行两种操作等待和发送信号, 即 P(sv)和 V(sv),他们的行为是这样的:
        P(sv): 如果 sv 的值大于零, 就给它减 1; 如果它的值为零, 就挂起该进程的执行
       V(sv): 如果有其他进程因等待 sv 而被挂起, 就让它恢复运行, 如果没有进程因等待 sv 而挂起, 就给它加 1。
        举个例子, 就是两个进程共享信号量 sv, 一旦其中一个进程执行了 P(sv)操作, 它将得到信号量, 并可以进入临界区, 使 sv 减 1。 而第二个进程将被阻止进入临界区, 因为当它试图执行 P(sv)时, sv 为 0, 它会被挂起以等待第一个进程离开临界区域并执行 V(sv)释放信号量, 这时第二个进程就可以恢复执行。
        信号灯也叫信号量, 它能够用来同步进程的动作, 不能传输数据。 它的应用场景就像红绿灯, 控制各进程使用共享资源的顺序。 Posix 无名信号灯用于线程同步, Posix 有名信号灯, System V 信号灯。 信号灯相当于一个值大于或等于 0 计数器, 信号灯值大于 0, 进程就可以申请资源, 信号灯值-1, 如果信号灯值为0, 一个进程还想对它进行-1, 那么这个进程就会阻塞, 直到信号灯值大于 1。
        使用 System V 信号灯的步骤如下:
       1. 使用 semget()创建或打开一个信号灯集。
       2. 使用 semctl()初始化信号灯集 。
       3. 使用 semop()操作信号灯值, 即进行 P/V 操作。
       P 操作: 申请资源, 申清完后信号灯值-1;
      V 操作: 释放资源, 释放资源后信号灯值+1;
       Linux 提供了一组精心设计的信号量接口来对信号进行操作, 它们不只是针对二进制信号量, 下面将会对这些函数进行介绍, 但请注意, 这些函数都是用来对成组的信号量值进行操作的。 它们声明在头文件sys/sem.h 中。

函数int semget(key_t key, int nsems, int semflg)
头文件#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
参数 key_t key信号量的键值
参数 int nsems信号量的数量
参数 int semflg标识
返回值成功返回信号量的 ID, 失败返回-1
功能创建一个新信号量或取得一个已有信号量
函数int semctl(int semid, int semnum, int cmd, union semun arg)
头文件#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
参数 int semid信号量 ID
参数 int semnum信号量编号
参数 cmdIPC_STAT(获取信号量的属性) IPC_SET(设置信号量的属性)IPC_RMID (删除信号量)
SETVAL(设置信号量的值)
参数 argunion semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
}
功能初始化信号灯集合
函数int semop(int semid, struct sembuf *sops, size_t nsops)
头文件#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
参数 int semid信号量 ID
参数 struct sembuf *sops信号量结构体数组
参数 size_t nsops要操作信号量的数量
struct sembuf{
unsigned short sem_num; //要操作的信号量的编号
short sem_op; //P/V 操作, 1 为 V 操作, 释放资源。 -1 为 P
操作, 分配资源。 0 为等待, 直到信号量的值变成 0
short sem_flg; //0 表示阻塞, IPC_NOWAIT 表示非阻塞
}
功能在信号量上执行一个或多个操作。

实验代码:
指定哪个进程运行,可以使用进程间通信的知识, 或者使用信号量, 这里以使用信号量为例:
 

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
union semun
{
    int val;
};

int main(void)
{
    int semid;
    int key;
    pid_t pid;
    struct sembuf sem;
    union semun semun_union;
    key = ftok("./a.c", 0666);
    semid = semget(key, 1, 0666 | IPC_CREAT);
    semun_union.val = 0;
    semctl(semid, 0, SETVAL, semun_union);
    pid = fork();
    if (pid > 0)
    {
         sem.sem_num = 0;
         sem.sem_op = -1;
         sem.sem_flg = 0;
         semop(semid, &sem, 1);
         printf("This is parents\n");
         sem.sem_num = 0;
         sem.sem_op = 1;
         sem.sem_flg = 0;
         semop(semid, &sem, 1);
    } 
    if (pid == 0)
    {
        sleep(2);
        sem.sem_num = 0;
        sem.sem_op = 1;
        sem.sem_flg = 0;
        semop(semid, &sem, 1);
        printf("This is son\n");
    } 
    return 0;
}

编译运行程序如下图所示:

        信号量是一个特殊的变量, 程序对其访问都是原子操作, 且只允许对它进行等待(即 P(信号变量))和发送(即 V(信号变量))信息操作。 我们通常通过信号来解决多个进程对同一资源的访问竞争的问题, 使在任一时刻只能有一个执行线程访问代码的临界区域, 也可以说它是协调进程间的对同一资源的访问权, 也就是用于同步进程的。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木士易

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值