Semaphore / 信号计数量[Version-2] / Sema的工作原理

  • Introduction : Semaphore(后面简称Sema)是在多线程锁中常常用到的锁的一种

STEP-1-生成一些Sema

方式1 -> 生成key + 生成Sema集合

创建semaphore的集合:semget() - 返回Sema集合的id

#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);
  • key:由不同的进程去识别这个sema集合的一个标识符
    • fname是指定的文件名,这个文件必须是存在而且可以访问的
  • nsems: 集合里sema的数量
  • semflg:这个告诉semget集合应该有什么样的许可(例如可读可写这样的权限集合)
//示例:先生成key,再生成Sema集合并将id返回来
key_t key;
int semid;

key = ftok("/home/beej/somefile", 'E');
semid = semget(key, 10, 0666 | IPC_CREAT)
  • 可以看到这里的ftok用的是这个文件名,在实际练习中,key=123这样赋值的方式也是可以的,但是为了正规操作,推荐还是使用ftok的方式获得
  • 这些刚刚生成的Sema们还没有被初始化,创造一些可以被使用的Sema不是一步就能完成的

方式2 -> 直接声明 + 直接初始化

var s:Semaphore  
...
init (s,1)
  • init(s,i)代表首先将关于sema的初始计数设置成 i + sema的队列={ }
    • 也就是init之后关于sema的队列被设置成全空

STEP-2-利用你的Sema们

内容1 -> 利用semctl去初始化sema集合中的特定sema

一旦创建了Sema集合,把他们初始化成一些值,使得他们可以获取到资源

//方程semctl允许你去修改sema集合中某一个sema的值

int semctl(int semid, int semnum, int cmd, ... /*arg*/)
  • semid是你刚刚在创建sema集合的时候返回的Sema集合的id
  • senum是你想改变值的那个sema的id
    • [目前还没搞清楚这个sema集合里的某个特定sema的id应该是什么样的]
  • cmd是指你想对这个sema执行什么样的操作
  • /args/,在需要使用的情况下是一个union semun,而semun形式如下
union semun {
    int val;               /* 仅仅在cmd是SETVAL的时候写上 */
    struct semid_ds *buf;  /* 用于 IPC_STAT 与 IPC_SET */
    ushort *array;         /* 用于 GETALL 用于 SETALL */
};
cmd命令集
SETVAL                  将特定的sema值设定成上面的val
GETVAL                  返回给定sema的值
SETALL                  将sema集合的值设定成上面array数组里的值
GETALL                  将sema集合的值收集起来存到上面的array数组里
IPC_RMID                将这个sema集合删除

PART-2 -> Sema工作原理解释

所以为什么要创建Sema集合?

// 首先看init(s,i) / semctl 中我们将某个sema的值设定成i
    - semaphore的初值代表一次能有多少个线程能接触到共享资源
    - 同时也代表了,能有多少线程执行下去不被阻挡

//其次再看down(s)的执行规则 ->  if( counter(s)>0 )  counter(s)-=1;
                              else -> add P to queue(s)
                                      suspend current process P

//最后再看up(s)的执行规则 ->  如果queue非空 
                              -> resume one process in queue(s)
                           如果queue为空 
                              -> counter+=1;
  • 简单介绍就是说:所谓放下来(down)也就是
    • -> 在count大于0的时候放进去,小于0的时候进不去(获得不到共享资源)
    • -> 进去以后就可以往公共资源里添加内容了,或者修改公共资源
  • 所谓升起来(up)也就是给队列中的数量加一
  • 正好进入的时候减一,退出的时候加一抵消

这一套利用semctl也是可以使用的

struct sembuf[]={num,-1,SEM_UNDO}
sem(id,op,1)       ->  等价于down

struct sembuf[]={num,1,SEM_UNDO}
semop(id,op,1)      ->等价于up

另一种方式执行sema的初始化:semop()

struct sembuf {
    ushort sem_num;        ->在这个sema集合里你想操作的sema的数量
    short sem_op;          ->你想执行的操作
    short sem_flg;
};

更多关于semop()使用方法点击这里 <-


最后,删掉一个sema集合: semctl(semid,0,IPC_RMID)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值