技术标签: semget Linux环境高级编程 semop System V信号量 信号量 semctl
信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。
在实际应用中两个进程间通信可能会使用多个信号量,因此 System V 的信号量以集合的概念来管理,具体操作和 Posix 信号量大同小异 。
信号量集合数据结构:struct semid_ds,此数据结构中定义了整个信号量集的基本属性。
/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct semid_ds
{
struct ipc_perm sem_perm; /* permissions .. see ipc.h */
__kernel_time_t sem_otime; /* last semop time */
__kernel_time_t sem_ctime; /* last change time */
struct sem *sem_base; /* ptr to first semaphore in array */
struct sem_queue *sem_pending; /* pending operations to be processed */
struct sem_queue **sem_pending_last; /* last pending operation */
struct sem_undo *undo; /* undo requests on this array */
unsigned short sem_nsems; /* no. of semaphores in array */
};
信号量数据结构:struct sem,此数据结构中定义了信号量的基本属性。
/* One semaphore structure for each semaphore in the system. */
struct sem
{
int semval; /* current value *信号量的值*/
int sempid; /* pid of last operation *最后一个操作信号量的进程号*/
struct list_head sem_pending; /* pending single-sop operations */
};
查看信号量数组
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcs -s
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$
删除信号量数组
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcrm -s semid
int semget(key_t key, int nsems, int semflg);
功能:
创建或打开一个信号量集合,该集合中可以包含多个信号量。
参数:
key:进程间通信键值,通过调用 ftok() 函数得到的键值
nsems:创建的信号量的个数。如果只是访问而不创建则可以指定该参数为 0,一旦创建了该信号量,
就不能更改其信号量个数,只要不删除该信号量,重新调用该函数创建该键值的信号量,
该函数只是返回以前创建的值,不会重新创建。
semflg:标识函数的行为及信号量的权限,其取值如下:
IPC_CREAT:创建信号量。
IPC_EXCL:检测信号量是否存在。
位或权限位:信号量位或权限位后可以设置信号量的访问权限,格式和 open 函数的 mode_ t
一样(open() 的使用请点此链接),但可执行权限未使用。
返回值:
成功:信号量集标识符
失败:返回 -1
int semctl(int semid, int semnum, int cmd, ...);
功能:
对信号量集合以及集合中的信号量进行操作。
参数:
semid:信号量集标识符。
semnum:集合中信号量的序号,指定对哪个信号量操作, 只对几个特殊的 cmd 操作有意义。
cmd:信号量控制类型。semctl() 函数可能有3个参数,也可能有4个参数,参数的个数由 cmd 决定。
当有4个参数时,第4个参数为联合体:
union semun{
int val; /*信号量的值*/
struct semid_ds *buf; /*信号量集合信息*/
unsigned short *array;/*信号量值的数组*/
struct seminfo *__buf;/*信号量限制信息*/
};
cmd 的取值如下:
GETVAL:获取信号量的值。此时函数有3个参数。semctl() 函数的返回值即为信号量的值。
SETVAL:设置信号量的值。此时函数有4个参数。第4个参数为联合体中的val,其值为信号量的值。
IPC_STAT:获取信号量集合的信息。此时函数有4个参数。第4个参数为联合体中的__buf。
IPC_SET:设置信号量集合的信息。此时函数有4个参数。第4个参数为联合体中的__buf。
IPC_RMID:删除信号量集。此时函数有3个参数,第2个参数semnum不起作用。
GETALL:获取所有信号量的值。此时函数有4个参数,第2个参数semnum不起作用。
第4个参数为联合体中的array,其值为用来存放所有信号量值的数组的首地址。
SETALL:设置所有信号量的值 。参数说明同上。
IPC_INFO:获取信号量集合的限制信息。此时函数有4个参数,第2个参数semnum不起作用。
第4个参数为联合体中的__buf。
GETPID:获取信号的进程号,即最后操作信号量的进程。此时函数有3个参数。
semctl() 函数的返回值即为信号的进程号。
GETNCNT:获取等待信号的值递增的进程数。此时函数有3个参数。semctl() 函数的返回值即为进程数。
GETZCNT:获取等待信号的值递减的进程数。此时函数有3个参数。semctl() 函数的返回值即为进程数。
返回值:
成功:0
失败:-1
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:
操作信号量,主要进行信号量加减操作。
参数:
semid:信号量集标识符。
sops:操作信号量的结构体(struct sembuf)数组的首地址( 结构体定义在 sys/sem.h ),
此结构体中的数据表明了对信号量进行的操作。
struct sembuf{
unsigned short sem_num; /*信号量的序号*/
short sem_op; /*信号量的操作值*/
short sem_flg; /*信号量的操作标识*/
};
结构体成员使用说明如下:
sem_num:信号量集中信号量的序号
sem_op 取值如下:
sem_op > 0:信号量的值在原来的基础上加上此值。
sem_op < 0:如果信号量的值小于 semop 的绝对值,则挂起操作进程。
如果信号量的值大于等于 semop 的绝对值,
则信号量的值在原来的基础上减去 semop 的绝对值。
sem_op = 0:对信号量的值进行是否为 0 测试。若为 0 则函数立即返回,若不为 0 则阻塞调用进程。
sem_flag 取值如下:
IPC_NOWAIT:在对信号量的操作不能执行的情况下使函数立即返回。
SEM_UNDO:当进程退出后,该进程对信号量进行的操作将被撤销。
nsops:操作信号量的结构体数组中元素的个数。
返回值:
成功:0
失败:-1
4.1 创建和删除信号量数组
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
key_t key;
//创建key值
key = ftok(".", 'a');
if(key == -1)
{
perror("ftok");
}
//查看信号量
system("ipcs -s");
int semid;
//1: 创建的信号量的个数
semid = semget(key, 1, IPC_CREAT|0666); //创建信号量
if(semid == -1)
{
perror("semget");
}
system("ipcs -s"); //查看信号量
//删去信号量
// 0: 代表对第0个信号量进行操作
// IPC_RMID:删除信号量集
semctl(semid, 0, IPC_RMID);
system("ipcs -s"); //查看信号量
return 0;
}
执行结果:
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
0x61320009 0 deng 666 1
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$
4.2 获取信号量数组相关信息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
/*解决编译出错的问题*/
#define IPC_INFO 3
int main(int argc, char *argv[])
{
key_t key;
//创建key值
key = ftok(".", 'a');
if(key == -1)
{
perror("ftok");
}
system("ipcs -s"); //查看信号量
int semid;
//1: 创建的信号量的个数
semid = semget(key, 1, IPC_CREAT|0666);//创建信号量
if(semid == -1)
{
perror("semget");
}
system("ipcs -s"); //查看信号量
struct seminfo buf;
/*
//struct seminfo相关成员
struct seminfo {
int semmap;
int semmni;
int semmns;
int semmnu;
int semmsl;
int semopm;
int semume;
int semusz;
int semvmx;
int semaem;
};
*/
//IPC_INFO:获取信号量集合的限制信息。
//此时函数有4个参数,第2个参数semnum不起作用。
semctl(semid, 0, IPC_INFO, &buf);
printf("buf.semmni = %d\n", buf.semmni);
printf("buf.semmns = %d\n", buf.semmns);
printf("buf.semmnu = %d\n", buf.semmnu);
printf("buf.semmsl = %d\n", buf.semmsl);
printf("buf.semopm = %d\n", buf.semopm);
printf("buf.semume = %d\n", buf.semume);
printf("buf.semusz = %d\n", buf.semusz);
printf("buf.semvmx = %d\n", buf.semvmx);
printf("buf.semaem = %d\n", buf.semaem);
//删去信号量
// 0: 代表对第0个信号量进行操作
// IPC_RMID:删除信号量集
semctl(semid, 0, IPC_RMID);
system("ipcs -s"); //查看信号量
return 0;
}
测试结果:
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
0x61320009 32768 deng 666 1
buf.semmni = 32000
buf.semmns = 1024000000
buf.semmnu = 1024000000
buf.semmsl = 32000
buf.semopm = 500
buf.semume = 500
buf.semusz = 20
buf.semvmx = 32767
buf.semaem = 32767
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$
4.3 获取和设置信号量数组的值
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
key_t key;
//创建key值
key = ftok(".", 'a');
if(key == -1)
{
perror("ftok");
}
//查看信号量
system("ipcs -s");
int semid;
//1: 创建的信号量的个数
semid = semget(key, 1, IPC_CREAT|0666); //创建信号量
if(semid == -1)
{
perror("semget");
}
system("ipcs -s"); //查看信号量
int ret;
/*
//SETVAL: 设置信号量的值。此时函数有4个参数。第4个参数为联合体中的val,其值为信号量的值。
union semun{
int val; //信号量的值
struct semid_ds *buf; //信号量集合信息
unsigned short *array; //信号量值的数组
struct seminfo *__buf; //信号量限制信息
};
*/
ret = semctl(semid, 0, SETVAL, 20);
if(ret == -1)
{
perror("semctl");
}
//GETVAL:获取信号量的值。函数返回值即为信号量的值。
ret = semctl(semid, 0, GETVAL);
if(ret == -1)
{
perror("semctl");
}
printf("ret = %d\n", ret);
// 0: 代表对第0个信号量进行操作
// IPC_RMID:删除信号量集
semctl(semid, 0, IPC_RMID);
system("ipcs -s");
return 0;
}
测试结果:
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
0x61320009 65536 deng 666 1
ret = 20
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$
4.4 信号量数组
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
key_t key;
//创建key值
key = ftok(".", 'a');
if(key == -1)
{
perror("ftok");
}
//查看信号量
system("ipcs -s");
int semid;
//2: 创建的信号量的个数
semid = semget(key, 2, IPC_CREAT|0666); //创建信号量
if(semid == -1)
{
perror("semget");
}
system("ipcs -s"); //查看信号量
int ret;
unsigned short sem_arry[2] = {
30,20};
/*
//SETALL: 设置所有信号量的值。此时函数有4个参数,第2个参数semnum不起作用。第4个参数为联合体中的array,其值为用来存放所有信号量值的数组的首地址。
union semun{
int val; //信号量的值
struct semid_ds *buf; //信号量集合信息
unsigned short *array; //信号量值的数组
struct seminfo *__buf; //信号量限制信息
};
*/
ret = semctl(semid, 0, SETALL, sem_arry);
if(ret == -1)
{
perror("semctl");
}
bzero(sem_arry, sizeof(sem_arry));
//GETALL:获取所有信号量的值。此时函数有4个参数,
//第2个参数semnum不起作用。第4个参数为联合体中的array,
//其值为用来存放所有信号量值的数组的首地址。
ret = semctl(semid, 0, GETALL, sem_arry);
if(ret == -1)
{
perror("semctl");
}
printf("sem_arry[0] = %d\n", sem_arry[0]);
printf("sem_arry[1] = %d\n", sem_arry[1]);
// IPC_RMID:删除信号量集
semctl(semid, 0, IPC_RMID);
system("ipcs -s");
return 0;
}
测试结果:
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
0x61320009 98304 deng 666 2
sem_arry[0] = 30
sem_arry[1] = 20
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$
4.5 综合实例
//此范例使用信号量来同步共享内存的操作
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/wait.h>
#define SHM_KEY 0x33
#define SEM_KEY 0x44
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int P(int semid)
{
struct sembuf sb;
/*
//操作信号量的结构体
struct sembuf{
unsigned short sem_num;//信号量的序号
short sem_op; //信号量的操作值
short sem_flg; //信号量的操作标识
};
*/
sb.sem_num = 0;
sb.sem_op = -1;
//SEM_UNDO:当进程退出后,该进程对信号量进行的操作将被撤销。
sb.sem_flg = SEM_UNDO;
//操作1个信号量
if(semop(semid, &sb, 1) == -1){
perror("semop");
return -1;
}
return 0;
}
int V(int semid)
{
struct sembuf sb;
/*
//操作信号量的结构体
struct sembuf{
unsigned short sem_num;//信号量的序号
short sem_op; //信号量的操作值
short sem_flg; //信号量的操作标识
};
*/
sb.sem_num = 0;
sb.sem_op = 1;
//SEM_UNDO:当进程退出后,该进程对信号量进行的操作将被撤销。
sb.sem_flg = SEM_UNDO;
//操作1个信号量
if(semop(semid, &sb, 1) == -1){
perror("semop");
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
pid_t pid;
int i, shmid, semid;
int *ptr = NULL;
union semun semopts;
/*
union semun{
int val; //信号量的值
struct semid_ds *buf; //信号量集合信息
unsigned short *array; //信号量值的数组
struct seminfo *__buf; //信号量限制信息
};
*/
//创建一块共享内存, 存一个int变量
if ((shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0600)) == -1) {
perror("msgget");
return -1;
}
//将共享内存映射到进程, fork后子进程可以继承映射
ptr = (int *)shmat(shmid, NULL, 0);
if (ptr == (int *)-1) {
perror("shmat");
return -1;
}
*ptr = 0; //赋值为0
// 创建一个信号量用来同步共享内存的操作
if ((semid = semget(SEM_KEY, 1, IPC_CREAT | 0600)) == -1) {
perror("semget");
return -1;
}
//初始化信号量
semopts.val = 1;
if (semctl(semid, 0, SETVAL, semopts) < 0) {
perror("semctl");
return -1;
}
if ((pid = fork()) < 0) {
//创建进程
perror("fork");
_exit(0);
}else if (pid == 0){
// Child
// 子进程对共享内存加1
for (i = 0; i < 100000; i++) {
P(semid);
(*ptr)++;
V(semid);
printf("child: %d\n", *ptr);
}
} else {
//Parent
// 父进程对共享内存减1
for (i = 0; i < 100000; i++) {
P(semid);
(*ptr)--;
V(semid);
printf("parent: %d\n", *ptr);
}
//如果子进程结束,回收其资源
wait(NULL);
//如果同步成功, 共享内存的值为0
printf("finally: %d\n", *ptr);
}
return 0;
}
执行结果:
child: -30
child: -29
child: -28
child: -27
child: -26
child: -25
child: -24
child: -23
child: -22
child: -21
child: -20
child: -19
child: -18
child: -17
child: -16
child: -15
child: -14
child: -13
child: -12
child: -11
child: -10
child: -9
child: -8
child: -7
child: -6
child: -5
child: -4
child: -3
child: -2
child: -1
child: 0
finally: 0
文章浏览阅读101次。4.class可以有⽆参的构造函数,struct不可以,必须是有参的构造函数,⽽且在有参的构造函数必须初始。2.Struct适⽤于作为经常使⽤的⼀些数据组合成的新类型,表示诸如点、矩形等主要⽤来存储数据的轻量。1.Class⽐较适合⼤的和复杂的数据,表现抽象和多级别的对象层次时。2.class允许继承、被继承,struct不允许,只能继承接⼝。3.Struct有性能优势,Class有⾯向对象的扩展优势。3.class可以初始化变量,struct不可以。1.class是引⽤类型,struct是值类型。
文章浏览阅读586次。想实现的功能是点击顶部按钮之后按关键字进行搜索,已经可以从服务器收到反馈的json信息,但从json信息的解析开始就会闪退,加载listview也不知道行不行public abstract class loadlistview{public ListView plv;public String js;public int listlength;public int listvisit;public..._rton转json为什么会闪退
文章浏览阅读219次。如何使用wordnet词典,得到英文句子的同义句_get_synonyms wordnet
文章浏览阅读521次。系统项目报表导出 导出任务队列表 + 定时扫描 + 多线程_积木报表 多线程
文章浏览阅读1.1k次,点赞9次,收藏9次。使用AJAX技术的好处之一是它能够提供更好的用户体验,因为它允许在不重新加载整个页面的情况下更新网页的某一部分。另外,AJAX还使得开发人员能够创建更复杂、更动态的Web应用程序,因为它们可以在后台与服务器进行通信,而不需要打断用户的浏览体验。在Web开发中,AJAX(Asynchronous JavaScript and XML)是一种常用的技术,用于在不重新加载整个页面的情况下,从服务器获取数据并更新网页的某一部分。使用AJAX,你可以创建异步请求,从而提供更快的响应和更好的用户体验。_ajax 获取http数据
文章浏览阅读2.8k次。登录退出、修改密码、关机重启_字符终端
文章浏览阅读3.8k次,点赞3次,收藏51次。前段时间看到一位发烧友制作的超声波雷达扫描神器,用到了Arduino和Processing,可惜啊,我不会Processing更看不懂人家的程序,咋办呢?嘿嘿,所以我就换了个思路解决,因为我会一点Python啊,那就动手吧!在做这个案例之前先要搞明白一个问题:怎么将Arduino通过超声波检测到的距离反馈到Python端?这个嘛,我首先想到了串行通信接口。没错!就是串口。只要Arduino将数据发送给COM口,然后Python能从COM口读取到这个数据就可以啦!我先写了一个测试程序试了一下,OK!搞定_超声波扫描建模 python库
文章浏览阅读4.2k次。端—端加密指信息由发送端自动加密,并且由TCP/IP进行数据包封装,然后作为不可阅读和不可识别的数据穿过互联网,当这些信息到达目的地,将被自动重组、解密,而成为可读的数据。不可逆加密算法的特征是加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,只有重新输入明文,并再次经过同样不可逆的加密算法处理,得到相同的加密密文并被系统重新识别后,才能真正解密。2.使用时,加密者查找明文字母表中需要加密的消息中的每一个字母所在位置,并且写下密文字母表中对应的字母。_凯撒加密
文章浏览阅读5.7k次。CIP报文解析常用到的几个字段:普通类型服务类型:[0x00], CIP对象:[0x02 Message Router], ioi segments:[XX]PCCC(带cmd和func)服务类型:[0x00], CIP对象:[0x02 Message Router], cmd:[0x101], fnc:[0x101]..._cip协议embedded_service_error
文章浏览阅读2.4k次,点赞9次,收藏13次。有时候我们在MFC项目开发过程中,需要用到一些微软已经提供的功能,如VC++使用EXCEL功能,这时候我们就能直接通过VS2019到如EXCEL.EXE方式,生成对应的OLE头文件,然后直接使用功能,那么,我们上篇文章中介绍了vs2017及以前的版本如何来添加。但由于微软某些方面考虑,这种方式已被放弃。从上图中可以看出,这一功能,在从vs2017版本15.9开始,后续版本已经删除了此功能。那么我们如果仍需要此功能,我们如何在新版本中添加呢。_vs添加mfc库
文章浏览阅读785次。用ac3编码,执行编码函数时报错入如下:[ac3 @ 0x7fed7800f200] frame_size (1536) was not respected for anon-last frame (avcodec_encode_audio2)用ac3编码时每次送入编码器的音频采样数应该是1536个采样,不然就会报上述错误。这个数字并非刻意固定,而是跟ac3内部的编码算法原理相关。全网找不到,国内音视频之路还有很长的路,音视频人一起加油吧~......_frame_size (1024) was not respected for a non-last frame
文章浏览阅读230次,点赞2次,收藏2次。创建Android应用程序一个项目里面可以有很多模块,而每一个模块就对应了一个应用程序。项目结构介绍_在安卓移动应用开发中要在活动类文件中声迷你一个复选框变量