首页 > 编程知识 正文

信号量机制wait和signal,信号量的取值范围怎么算

时间:2023-05-05 17:20:39 阅读:113438 作者:1966

一、首先,有必要知道信号量是什么吗?

信号的本质是数据操作锁,它本身不具有数据交换的功能,而是通过控制其他通信资源(文件、外部设备)来实现进程间通信,它本身只是外部资源的标识。 信号在这个过程中负责数据操作的互斥、同步等功能。

这是书中介绍的信号量概念,自己的理解比较简单:

信号是指原子性的计数器,相当于密钥。 在每个进程访问关键资源时,信号必须具有密钥”。 信号进入名为关键资源的“房间”,锁上门以防其他过程进入。 此时信号为p ) )执行操作,锁定数量减少了一个,因此计数器减少1。 访问完成后,它出现,将锁定返回信号量(v ) )并执行操作,将计数器加1。 然后下一个过程继续。 这表明每个进程访问临时资源是互斥的。

“原子性”:表示一件事的两种状态,做了也不是做了;

“计数器”:信号量通常描述临界资源的数量; 同时,信号量本身是临界资源,旨在保护临界资源,解决数据不一致问题;

“临界资源”:在不同过程中看到的共同资源;

关键区域:多个进程访问关键资源的代码;

互斥:临时资源只能访问一个临时区域,属性为原子。

二、为什么要用信号量

为了防止多个程序同时访问一个共享资源而引起的一系列问题,需要一种可以通过生成和使用令牌进行授权的方法。 此外,一次只能有一个极限空间让执行线程访问代码。 关键节是以独占方式运行执行数据更新的代码。 信号提供一种访问机制,使一个线程同时只能访问某个关键节。 也就是说,信号用于协调进程对共享资源的访问。 其中共享内存的使用需要信号量。

三.编写程序实例

如果两个进程分别在显示器(linux下的所有文件、关键资源)上打印AA和BB,但未使用信号保护,则数据可能会变得混乱,如“AABBABAAAB .”。 为了解决这个问题,创建并保护信号。 打印“AA”或“BB”。

要编写代码界面:

创建信号量creat_sems:

key:ftok函数生成

第一个参数_key,为整型值,是允许其他的进程访问信号量的一个整型的变量。所以的信号都是通过间接的方式获得的,运行的程序会提供一个信号的键值,系统为每一个键值赋予一个信号量,其他的处理函数只能通过对semget函数的返回值进行处理。

第二个参数_nsems,参数表示信号量的编号,几乎总是取值为1.

第三个参数_semflg,信号量的权限。

与打开操作和参数semflg的内容相关。 如果系统内核中不存在IPC_CREAT信号偏移,请创建信号偏移。 与IPC_exclIPC_creat一起使用时,如果信号偏移已经存在,则调用将失败。 如果单独使用IPC_CREAT,semget ()将返回新创建的信号偏移的标识符,或返回系统中已存在的具有相同关键字值的信号偏移的标识符。 如果要将IPC_EXCL与IPC_CREAT一起使用,则返回新创建的信号偏移的标识符或返回-1。 单独使用IPC_EXCL没有意义。 参数nsems指示要用新信号偏移创建的信号数。

丢弃信号量destory_sems ()

功能:控制信号量的信息

返回值:成功返回0,失败返回-1

ding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> 第一个参数semid:信号量标识码,还是通过semget来获得的,是semget函数的一个返回值

第二个参数semnum:信号量的编号,当用到信号量数组的时候,这个编号就会起到作用

第三个参数cmd:为允许的命令

第四个参数是个联合体:


初始化信号量init_sem()

与销毁信号量所用函数相同,但参数不同


p、v操作:


函数功能:用户改变信号量的值.

返回值:函数调用成功返回0,失败返回-1

参数semid:系统分配给该信号量的一个ID号,通过semget函数的返回值来获得,也称为信号的标识码

参数sops:一个指向信号量结构体数组的指针,信号量的结构体至少有3个成员。

nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作

注意这里的结构体sembuf


struct sembuf

{

unsigned short sem_num;操作信号在信号集中的编号,第一个信号的编号为0,第二个为1,一次后推

short sem_op;信号资源,如果有就分配,如果为负值就等待(wait),如果正值就分配信号资源

short sem_flg;信号操作标志,有两种状态,一个是SEM_UNDO,另一个是SEM_NOWAIT

}

SEM_NOWAIT//对信号的操作不能满足是,semop()函数就会阻塞,并立即返回,同时设置错误信息。

SEM_UNDO//程序结束时(无论是否正常结束),保证信号值会被重新设为semop()调用前的值。这样做

的目的在于避免在异常情况下结束时未将锁定资源解锁,造成该资源永远锁定。


flag一般为0,若flag包含IPC_NOWAIT,则该操作为非阻塞操作。若flag包含SEM_UNDO,则当进程退出的时候会还原该进程的信号量操作,这个标志在某些情况下是很有用的,比如某进程做了P操作得到资源,但还没来得及做V操作时就异常退出了,此时,其他进程就只能都阻塞在P操作上,于是造成了死锁。若采取SEM_UNDO标志,就可以避免因为进程异常退出而造成的死锁。


下面写一个小例子声明一个结构体:

 struct sembuf sem1_opt_wakeup[1]={0,1,SEM_UNDO};

 struct sembuf sem1_opt_wait[1]={1,-1,SEM_UNDO};


    只有将 sem_flg 指定为 SEM_UNDO 标志后,semadj (所指定信号量针对调用进程的调整值)才会更新。   此外,如果此操作指定SEM_UNDO,系统更新过程中会撤消此信号灯的计数(semadj)。此操作可以随时进行---它永远不会强制等待的过程。调用进程必须有改变信号量集的权限。


验证信号量的实例:

comn.h文件


comn.c文件:

各函数接口


test_sems测试文件


版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。