1.先说一下 ,终端的命令
pcs 命令用于报告进程间通信方式的状态
语法
ipcs -m m 共享内存段
ipcs -q q 消息队列
ipcs -s s 信号量
ipcs -a a设施的类型。
2 ipcrm- 删除IPC
格式:ipcrm [–q msgid] [-m shmid] [ -s semid] [-Q msgkey] [-M shmkey] [-S semkey]
参数说明:
-q:通过msgid删除消息队列
-Q:通过msgkey删除消息队列
-m:通过shmid删除共享内存
-M:通过shkey删除共享内存
-s:通过semid删除信号量
-S:通过semkey删除信号量
3.信号量
信号量:一个整数;
大于或等于0时代表可供并发进程使用的资源实体数;
小于0时代表正在等待使用临界区的进程数;
用于互斥的信号量初始值应大于0;
只能通过P、V原语操作而改变;
信号量也就是操作系统中所用到的PV 原语,它广泛用于进程或线程间的同步与互斥。信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
PV原语的工作原理:PV原语是对整数计数器信号量sem的操作。一次P操作使sem减一,而一次V操作使sem 加一。
进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限。当信号量sem 的值大于等于零时,该进程(或线程)具有公共资源的访问权限;相反,当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号量sem的值大于0 为止。
为了达到安全访问共享资源的目的,就要同步共享资源,那么总要把访问的共享资源放在临界区中,能否进入临界区正好用信号量来控制, 进程需要执行下列操作: (1) 访问控制该资源的信号量 。 (2) 若此信号量的值为正,则允许进行使用该资源。进程将信号量减1(P操作) (3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。 (4) 当进程不再使用一个信号量控制的资源时,信号量值加1。(V操作),如果此时有进程正在睡眠等待此信号量,则唤醒此进程
4.
5.
6.信号函数:
1.ftok--获取一个IPC标识符
头文件: # include <sys/types.h> # include <sys/ipc.h>
函数原型:key_t ftok(const char *pathname, char proj_id);
参数:pathname为指定的文件路径,实际用到的是此文件的索引节点号,proj_id是子序号。
返回值:成功返回一个系统中唯一的key,否则返回-1
2.semget--获得一个信号量集合ID
头文件: #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
原型:int semget(key_t key, int nsems, int flag)
函数功能:用于创建一个新的信号量组或获取一个已经存在的信号量组
参数:key是IPC结构的标识符,
nsems是该集合中的信号量个数。如果是创建新集合(一般在服务器中),则必须指定
nsems;如果是引用一个现有的信号量集合(一般在客户机中)则将nsems指定为0。
flag将来决定是创建新的信号量集合,还是引用一个现有的信号量集合。flag常用值为:以下|权限值
IPC_CREAT 如果信号量不存在则创建
IPC_EXCL 与IPC_CREAT合用,如果信号量已经存在则返回错误
返回值:如果创建成功返回已创建信号量集标识符semid,如果不成功返回-1
所创建的信号量可以通过 ipcs –s 命令查询
3.semctl--实现对信号灯的各种控制操作
原型:int semctl(int semid, int semnum, int cmd, semun arg );
返回值:如果成功,则返回一个正数,否则返回-1
参数:semid指定信号量集,
semnum指定对哪个信号灯操作(从0开始),
参数cmd指定具体的操作类型。
参数cmd可为下列值: IPC_STAT获取信号量信息,信息由arg.buf返回,记录在semid_ds结构体 IPC_SET 设置信号量信息,待设置信息保存在arg.buf中。
IPC_RMID 将信号量集从内存中删除。
IPC_INFO 获取信息量集,由arg.buf返回,记录在struct seminfo结构体 GETALL 获取所有信号量的值,结果保存在 arg.array 中,
GETNCNT 返回正在等待资源的进程数目。
GETPID返回最后一个执行semop操作的进程的PID。
GETVAL返回信号量集中的一个单个的信号量的值
GETZCNT返回这在等待完全空闲的资源的进程数目(等待所有信号量值变成0的进程数)
SETALL 通过arg.array更新所有信号量的值,同时更新与本信号相关的semid_ds结构的sem_ctime成员。
SETVAL设置信号量semnum所代表的信号量的值为arg.val。
4.semop--操作单个信号量
原型int semop(int semid,struct sembuf*sops,unsign int nsops)
函数功能:函数可以一次对一个或多个信号量进行PV操作。
参数:semid为要操作的信号量集合标识符,由semget()返回得来
sops是指向将要操作的结构体的指针。
nsops规定该数组中操作的数量(元素数)。
sem_op可以是下列值:
sem_op>0:相应进程要释放sem_op数目的共享资源;(V操作)
sem_op=0:用于对共享资源是否已用完的测试;(导致操作阻塞,直到信号量的值为0才继续) sem_op<0:进程要申请sem_op个共享资源。(P操作,信号量的值减去绝对值,如果小于零,进程阻塞,直到信号量的值至少等于其绝对值)
sem_flg可以是下列值:
IPC_NOWAIT用于防止操作阻塞,如果操作本应阻塞,则semop调用会失败。
SEM_UNDO会在进程退出的时候自动撤消该次操作。 返回值:0,成功。-1,失败。
看看代码 (看代码就懂了 真的)
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:信号量的函数
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
//信号量函数的使用方法
//ls -li //查看键值(唯一对应的值)
//2.ftok //创建键值
//3.semget 获得一个信号灯
//终端:
//4. ipcrm -s 信号量 删除信号量
//5. ipcs -s 查看信号量
//信号量的命令
// ipcs -m
// ipcs -q
// ipcs -s
// ipcs -a
//6.semctl 实现对信号量的各种控制操作 设定灯的初始值,查看信号量
//
union semnum
{
int val;
}value={1};//初始的值为1
int main(int argc,char *argv[])
{
key_t key =ftok(".",50);//生成一个键 //50这里随便填
if(key==-1)
{
perror("ftok error\n");
return -1;
}
else
{
printf("ftok ok\n");
printf("key =%d\n",key);
}
int sid =semget(key,1,IPC_CREAT|0666); //创建一个信号量
printf("sid =%d\n",sid);//打印信号量的 id
//6 设定值 1
semctl(sid,0 ,SETVAL,value);//value 是上面的共用体 //初始化 开始是1
//查看初始化的值
int val1 = semctl(sid,0,GETVAL,0);
printf("val1 =%d\n",val1);
//P操作 v操作
//semop 函数
struct sembuf sem1 ={0};
sem1.sem_num=0; //创建的第一个信号量
sem1.sem_op=-1; //这里是-1 (注意)
sem1.sem_flg=0;
semop(sid ,&sem1,1); //p 操作
val1 = semctl(sid,0,GETVAL,0);//查看初始化的值
printf("p -> val1 =%d\n",val1);
//对临界资源操作
//v 操作
sem1.sem_op=1; //+1 开灯
semop(sid,&sem1,1);
val1 = semctl(sid,0,GETVAL,0);//查看初始化的值
printf("v -> val1 =%d\n",val1);
//销毁信号量
semctl(sid,0,IPC_RMID,0);
return 0;
}