IPC: 信号量

###################################################

信号量

 

信号量:在多线程环境下,用来保证多个关键代码不被并发调用,一次只能有个一个线程访问关键代码。

 

信号量有两组函数接口:

1.posix信号量

2.system v信号量

 

信号量的两种形式:

1.二进制信号量:用来保护一段代码,使其每次只能被一个执行线程运行,初始值一般为1.

2.计数信号量:有限数目的线程执行一段指定的代码,初始值一般大于1.

 

-----------------------------------------------------------

posix信号量:

 

posix信号量分两种:

1.posix有名信号量,一般用在无亲缘关系的进程间。

2.posix基于内存的信号量(无名信号量),一般用在不需要使用与有名信号量关联的名字。

 

gcc - lpthread

 

#include <semaphore.h>

#include <fcntl.h>

#include <sys/stat.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);

创建一个有名信号量。

value:信号量初始值。

 

int sem_close(sem_t *sem);

关闭有名信号量

 

int sem_unlink(const char*name);

删除有名信号量

 

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

初始化无名(基于内存)信号量;

 

pshared:

0:信号量在同一个进程间的线程间共享

非0:在进程间共享信号量

 

value:信号量的初始值

 

int sem_destroy(sem_t *sem);

销毁无名(基于内存)信号量

 

信号量等待操作,在使用信号量之前调用:

int sem_wait(sem_t *sem);

如果信号量值大于0,就减去1然后返回,如果信号量值等于0,就阻塞。

int sem_trywait(sem_t *sem);

等待操作的非阻塞版本,如果信号量值等于0,立即返回错误。

int sem_timedwait(sem_t *sem, conststruct timespec *abs_timeout);

阻塞指定的时间。

 

信号量挂出操作,在使用信号量之后调用

int sem_post(sem_t *sem);

将信号量的值加1.

 

获取信号量的值

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

返回信号量的当前值放入sval中,如果信号量已上锁返回0或某个负数,负数的绝对值表示等待该信号量解锁的进程数。

 

SEM_NSEMS_MAX:一个进程可以同时打开的最大信号量数目。

SME_VALUE_MAX:一个信号量的最大值。

 

-----------------------------------------------------------

system v信号量:

 

#include <sys/ipc.h>

#include <sys/sem.h>

#include <sys/types.h>

 

内核位system V维护一个信号量结构:

struct semid_ds {

    struct ipc_permsem_perm;

    struct sem*sem_base;//指向信号量集

    ushort sem_nsems;//初始化为nsems

    time_t sem_otime;//初始化为0

    time_t sem_ctime;//初始化为当前时间

}

 

struct sem {

    ushort_t semval; //信号量的值

    short sempid; //对semval值进行最后一次操作的进程ID

    ushort_t semncnt;//等待semval变为大于其当前值的线程数。

    ushort_t semzcnt;//等待semval变为0的线程数。

}

 

int semget(key_t key, int nsems, int semflg);

创建一个信号量集或访问一个已存在的信号量集,返回信号量标识符。

 

key:既可以是ftok的返回值,也可以是IPC_PRIVATE.

 

nsems:

指定集合中的信号量数,访问一个已存在信号量就置0.

 

semflg:

semflg: 可以用读写权限 或 其它可选权限。

0:打开已存在的

属主:SEM_R        SEM_A

属组:SEM_R >> 3   SEM_A >> 3

其它:SEM_R >> 6   SEM_A >> 6

IPC_CREAT:不存在就创建,存在就返回已存在的。

IPC_CREAT | IPC_EXCL:不存在就创建,存在就返回错误。

 

int semop(int semid, struct sembuf *sops, unsignednsops);

对信号量的操作,sops指向一个结构数组,nsops是数组元素个数。

 

struct sembuf {

    unsigned shortsem_num; //0-nsems 指定某个信号量

    short sem_op;

    short sem_flg;

};

 

sem_op: 决定做什么操作

0:等待semval变为0

1(正数):将该值加到semval上,如果semval已经为0,就返回。

-1(负数):等待semval变为大于或等于该值的绝对值。

 

sem_flg:

IPC_NOWAIT:给定信号量非阻塞

SEM_UNDO:指定该标识,semadj才会更新,

 

int semctl(int semid, int semnum, int cmd, (union semunarg …);

对一个信号量执行各种控制操作,semnum为0-nsems 为指定的某个信号量。

 

第四个参数由第三个参数决定,这个结构需要自己定义

union semun {

    int val;//SETVAL

    struct semid_ds*buf;//IPC_SET IPC_STAT

    ushort*array;//GETALL SETALL

} arg;

 

cmd:命令执行成功函数返回0,失败函数返回-1:

GETVAL:获取semval的值返回

GETPID:把sempid的当前值作为函数返回值

GETNCNT:把semncnt的当前值作为函数返回值

GETZCNT:把semzcnt的当前值作为函数返回值

IPC_RMID:把semid指定的信号量集从系统中删除

cmd取下列值才有第四个参数arg:

GETALL:通过arg.array返回指定信号量集内每个成员的semval。

SETALL:将arg.array中的值赋给信号量集中的每个semval。

SETVAL:将arg.val的值赋给semval。

IPC_STAT:通过arg.buf获取指定信号量集中当前semid_ds结构。

IPC_SET:用arg.buf设置指定信号集中semid_ds结构中的ipc_perm结构的三个成员。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值