一、获取信号量
用semget()函数获取信号量,其中semget()函数中所需传的参数如下:
semget(key_t key , int nsems, semflg);
参数解释:
1、其中key可以通过ftok() 函数进行获取,ftok函数所需传入的参数为①文件路径②一个八位的整数
2、nsems是所需创建的信号量的个数,如果只是访问已存在的信号量集合,可以将此参数设置为0。
3、semflg是一个标志参数,用于指定创建或访问信号量集合的方式,常用的标志有:
①IPC_CREAT:如果指定的键值对应的信号量集合不存在,则创建一个新的信号量集合。
②IPC_EXCL:与IPC_CREAT同时使用,如果指定的键值对应的信号量集合已经存在,则返回错误。
③0666:用于指定信号量集合的权限,表示允许所有用户读写信号量集合,这里也可以是填其它权限,如0664等,不一定是0666
具体实现:
int sem_creat(key_t key, int nsems)
{
int semid = semget(key, nsems, 0664|IPC_CREAT);//创建信号量
if(semid < 0){ //通过返回值判断信号量是否创建成功,小于零则创建失败,打印一下错误信息并退出
perror("semget");
exit(0);
}
return semid;
}
二、初始化信号量
用semctl来初始化信号量,其中semctl函数所需传入的参数如下:
int semctl(int semid, int semnum, int cmd, ...)
:
参数解释:
1、semid:信号量集合的标识符,通过smget函数获取(也就是上一步获取信号量的时候得到的)。
2、semnum:要操作的信号量在集合中的索引(也就是要初始化哪一个信号量),对于一个信号量集合可以有多个信号量,而semnum指定了要操作的具体信号量
3、cmd:指定要执行的命令,可以是以下几种之一:
①、GETVAL
:获取指定信号量的当前值。
②、SETVAL
:设置指定信号量的值。
③、IPC_RMID
:删除信号量集合。
④、IPC_STAT
:获取信号量集合的状态信息。
⑤、IPC_SET
:设置信号量集合的状态信息。
⑥、GETALL
:获取所有信号量的当前值。
⑦、SETALL
:设置所有信号量的值。
4、....:表示可变参数,根据不同的命令有不同的使用方式,需要注意的是。semctl函数的第四个参数arg的具体含义取决于使用命令和使用方式(也就是根据第三个参数来的),对于某些命令,arg是一个整数值,而对于其它命令,arg是一个指向union semun结构体的指针。在使用semctl函数时,需要根据具体的需求和命令来确定如何使用这个参数。
具体实现:
void init_sem(int semid,int semnum,int val)//初始化需要传semid和初始化哪个信号量,还有初始化的值
{
int ret;
union semun sem;//这个是根据第三个参数来的,semun联合体中有好多种数据类型
sem.val = val;
ret = semctl(semid,semnum,SETVAL,sem);//这里用的是SETVAL,所以要传第四个参数,也就是你要初始化的值
if(ret < 0)//判断是否初始化成功
{
perror("semctl");
exit(0);
}
}
注意: union semun联合体(也叫共用体)需要我们自己去实现,大概的样子长这样:
union semun {
int val; // 设置信号量的初始值或获取当前值
struct semid_ds *buf; // IPC_STAT 或 IPC_SET 时使用
unsigned short *array; // GETALL 或 SETALL 时使用
};
三、进行p操作(加锁操作)
用semop函数来进行加锁操作,semop函数传入的参数如下:
int semop(int semid, struct sembuf *sops, size_t nsops);
参数解释:
1、semid:是一个信号量集标识符,用于指定要操作的信号量集。在使用semget
函数创建信号量集后,会返回该标识符。
2、sops
:是一个指向sembuf
结构体数组的指针,每个sembuf
结构体表示对一个信号量的操作(也就是通过结构体来设置信号量当前的状态)。
sembuf结构体的定义如下:
struct sembuf {
unsigned short sem_num; // 信号量在信号量集中的索引
short sem_op; // 信号量的操作
short sem_flg; // 操作标志
};
其中
sem_num是要操作的信号量在信号量集中的索引,从0开始计数
sem_op
:是对信号量的操作,可以是正整数、负整数或零。
· 正整数表示将信号量的值增加相应的数量。
· 负整数表示将信号量的值减少相应的数量。
· 零表示等待信号量变为零。
sem_flg是操作标志,用于指定操作的行为,常见的取值有:
-
SEM_UNDO
:如果进程退出时仍然持有该信号量,则会自动释放。 -
IPC_NOWAIT
:如果无法立即执行操作,则函数会立即返回,并设置错误码为EAGAIN
。
3、nsops
:表示sembuf
结构体数组中元素的数量,即要进行操作的信号量的个数。
具体实现:
void sem_p(int semid,int semnum,size_t nsops)
{
struct sembuf sops;
sops.sem_num = semnum;//设置要操作哪个信号量
sops.sem_op = -1;//设置信号量要执行的操作,-1是上锁的操作,锁-1
sops.sem_flg = SEM_UNDO;//防止死锁‘
int ret = semop(semid,&sops,nsops);
if(ret < 0)//判断是否执行成功
{
perror("semop-p");
exit(0);
}
}
四、进行v操作(解锁操作)
进行v操作也是用的semop函数,只是传的参数不同,sops.sem_op = 1。文章来源:https://www.toymoban.com/news/detail-635275.html
具体实现:
void sem_v(int semnum,size_t nsops)
{
struct sembuf sops;
sops.sem_num = semnum;
sops.sem_op = +1;//与p操作不同的地方
sops.sem_flg = SEM_UNDO;
int ret = semop(semid,&sops,nsops);
if(ret < 0)
{
perror("semop-v");
exit(0);
}
}
五、释放信号量
释放信号量也可以用semctl()函数,只是传的参数有变化文章来源地址https://www.toymoban.com/news/detail-635275.html
具体实现:
void sem_destroy(int semid)
{
int ret = semctl(semid,-1,IPC_RMID);
if(ret < 0)
{
perror("semctl-rmid");
exit(0);
}
}
到了这里,关于C语言用信号量进行pv操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!