系统编程 day11 信号量 (我也不知道是什么东西,不好解释 )(和之前的信号有一些不同 (函数), 但是也有一些操作相同 ,比如说 p v 操作 , )

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;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值