0


【Linux】进程间通信 -- 信号量

概念引入

信号量是什么?
本质是一个计数器,通常用来表示公共资源中,资源数量多少的问题

公共资源:能被多个进程同时可以访问的资源

访问没有保护的公共资源:数据不一致问题(比如我想写abc123,但是我123还没有写入,就读取了abc,可能数据分开会导致数据无意义)
为什么要让不同的进程看到同一份资源呢?
因为我想通信,进程间实现协同。但是进程具有独立性,没有办法让两个进程直接通信,为了解决这种问题,解决办法就是让进程看到同一份资源,但是因为提出了这个方法,同时也引入了新的问题:数据不一致

我们将保护起来的公共资源称为:临界资源(大部分资源是独立的)

资源包括内存、文件、网络等,资源存在的意义就是要被使用,如何被进程使用呢?
一定是该进程有对应的代码来访问这部分临界资源(有临界区就有非临界区)

多进程在进行进程间通信时本质是要看到一份公共的资源,这部分公共资源在未来如果被保护起来,那么这部分公共资源我们就称其为临界资源,而访问该临界资源中我们自己的那部分代码我们叫做临界区,不访问临界资源那部分代码的我们叫做非临界区

如何保护资源:互斥与同步
原子性:要么不做,要做就做完,只有两种状态(不会被线程调度机制打断的操作)

为什么要信号量?

举例认识:比如我们看电影,我们不是只要坐在一个座位上,那么这个座位就属于你了,而是你要去买票,然后给你分配一个座位,这个座位才属于你,不管你去不去,你只要买票了,那么这个座位始终都会留给你,这种电影买票的本质:对放映厅中的座位进行预定机制。我们想要某种资源的时候也可以进行预定。

共享资源的使用:作为一个整体使用、划分为一个一个的子资源使用
我们想让不同的进程同时访问一份资源的不同区域,这样我们某种程度上能实现并发

假如我们将一份共享资源(电影院)分成几份,进程(人),访问共享资源的子部分(电影的座位),我们不能直接去访问这些资源(不能不买票随便坐),信号量(电影票),每个进程先申请信号量,如果申请成功了,就相当于预定这部分资源(买到票有座位),申请失败就不允许访问这部分资源(没买票到不允许看电影)。这种申请信号量方式以达到保护共享资源,约束其他进程的目的。信号量就是计数器(电影票是有限的),申请一个就少一个。

sem =20;//定义信号量总数

sem--;//预定资源//访问公共资源

sem++;//释放资源

PV操作:P → 预定资源 V → 释放资源

所有的进程在访问公共资源之前,都必须先申请sem信号量→必须先申请sem信号量的前提,是所有进程必须先得看到同一个信号量→信号量本身就是公共资源→信号量是不是也要保证自己的安全呢?

- -,++

→信号量必须保证自身操作的安全性,

- -,++

操作是原子! !

如果一个信号量初始值为1:二元信号量–互斥功能

思考:有没有可能两个进程都申请信号量成功了却访问同一个资源?
有的,申请信号量成功只能表明这个资源一定有部分是留给你访问的,但具体是哪一部分还需要确认。这部分的工作一般是由程序员来指定的


信号量操作接口

1.申请信号量semget

在这里插入图片描述
函数原型:

intsemget(key_t key,int nsems,int semflg);

函数参数:

  1. key:一个用于标识信号量集的键值,它必须是一个非零的整数。通常使用 ftok 函数来生成键值。
  2. nsems:信号量集中包含的信号量的数量。这个参数必须是一个大于零的整数。
  3. semflg:一个标志参数,用于指定信号量集的创建和访问权限。常见的标志包括:IPC_CREAT:如果指定的 key 值对应的信号量集不存在,则创建它。IPC_EXCL:如果同时指定了 IPC_CREAT 和 IPC_EXCL 标志,而对应的信号量集已经存在,则会出现错误。0666:指定新创建的信号量集的权限。这个参数使用八进制表示,表示该信号量集可以被所有用户读写。

函数返回值:
semget 函数的返回值是一个信号量集的标识符,也称为“信号量集描述符”。它是一个非负整数,可以用于后续的信号量操作函数中。

2.控制信号量semctl

在这里插入图片描述
函数原型:

intsemctl(int semid,int semnum,int cmd,...);

函数参数:

  1. semid:一个信号量集的标识符,它是由 semget 函数返回的。
  2. semnum:要操作的信号量在信号量集中的编号,从 0 开始计数。
  3. cmd:用于指定要执行的操作,常见的操作包括:GETVAL:获取指定信号量的当前值。SETVAL:设置指定信号量的值。IPC_RMID:删除指定的信号量集。IPC_STAT:获取指定信号量集的状态信息。IPC_SET:设置指定信号量集的状态信息。
  4. ... :可选参数,用于给 SETVAL 命令指定要设置的值。

函数返回值根据不同的命令而异:

  • 对于 GETVAL 命令,返回指定信号量的当前值。
  • 对于 SETVAL 命令,返回 0 表示操作成功,-1 表示操作失败。
  • 对于 IPC_RMID、IPC_STAT 和 IPC_SET 命令,返回 0 表示操作成功,-1 表示操作失败。

3.处理信号量semop

在这里插入图片描述

intsemop(int semid,structsembuf*sops,unsigned nsops);

函数参数:

  1. semid:一个信号量集的标识符,它是由 semget 函数返回的。
  2. sops:一个指向 sembuf 结构体数组的指针,每个结构体描述一个操作。sembuf 结构体定义如下:
structsembuf{unsignedshort sem_num;// 操作的信号量在信号量集中的编号short sem_op;// 操作的值short sem_flg;// 操作的标志};- `sem_num`:要操作的信号量在信号量集中的编号,从 0 开始计数。

- `sem_op`:要执行的操作,可以是一个正数、负数或零。

  - 如果 `sem_op` 是一个正数,表示对应的信号量的值将增加 `sem_op`。

  - 如果 `sem_op` 是一个负数,表示对应的信号量的值将减少 `sem_op`。

  - 如果 `sem_op` 是零,表示对应的信号量的值不变。

- `sem_flg`:操作的标志,包括:

  - `SEM_UNDO`:表示在进程异常终止时,内核将撤销该进程所做的所有操作。

  - `IPC_NOWAIT`:表示如果无法立即执行相应的操作,则立即返回。
  1. nsops:sops 数组中元素的数量。

函数返回值:
表示是否操作成功,如果成功则返回 0,如果失败则返回 -1。

IPC资源的组织方式

共享内存、消息队列、信号量它们的接口相似度很高,比如获取与删除

且它们开始都是定义:

structipc_perm{key_t          __key;/* Key supplied to shmget(2) */uid_t          uid;/* Effective UID of owner */gid_t          gid;/* Effective GID of owner */uid_t          cuid;/* Effective UID of creator */gid_t          cgid;/* Effective GID of creator */unsignedshort mode;/* Permissions + SHM_DEST and
                                SHM_LOCKED flags */unsignedshort __seq;/* Sequence number */};

在这里插入图片描述
对其进行操作:

(structshmid_ds*)perms[0]->其他的属性

structshmid_di myshm;
perms[0]=&myshm.shm_perm;structmsqid_ds mymsg;
perms[1]=&mymsg.msg_perm;

结构体的第一个成员的地址,在数字上和结构体对象本身的地址数字是相等的,我们就可以通过结构体的地址,强转

struct shmid_ds*

来使用其里面的其他属性,如上述伪代码。


如有错误或者不清楚的地方欢迎私信或者评论指出🚀🚀

标签: linux 服务器 运维

本文转载自: https://blog.csdn.net/DEXTERFUTIAN/article/details/131499038
版权归原作者 侠客cheems 所有, 如有侵权,请联系我们删除。

“【Linux】进程间通信 -- 信号量”的评论:

还没有评论