<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 7》(11)

本文主要是介绍<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 7》(11),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Linux操作系统原理分析之Linux 进程管理 7》(11)

  • 4 Linux 进程管理
    • 4.7 IPC 信号量机制
      • 4.7.1 信号量与信号量集合
        • 1.信号量
        • 2.信号量集合
        • 3.信号量集合的集中
      • 4.7.2 信号量集合的创建和检索
      • 4.7.3 信号量 PV 操作
      • 4.7.4 信号量操作等待队列
        • 1.信号量操作等待队列
        • 2.将信号量操作移出等待队列
      • 4.7.5 信号量控制操作
      • 4.7.6 信号量的程序例
        • 程序例 1:创建一个信号量集合,并对信号量进行 P 操作。
        • 程序例 2:通过信号量控制函数删除信号量集合。

4 Linux 进程管理

4.7 IPC 信号量机制

Linux 的信号量机制有两种:

1 其本身设置的信号量机制

2 引进 UNIX SYSTEM V 的 IPC(Internal Process Communication)中的信号量机制

IPC(Internal Process Communication)中的信号量机制其涉及到的函数和数据结构分别定义在 Linux 源文件的 ipc/sem.c 和 include/linux/sem.h

4.7.1 信号量与信号量集合

IPC 信号量机制更完善、更方便使用。

1.信号量

定义:
系统中每个信号量对应一个信号量结构体 sem,其定义如下:

Struct sem
{
Short semval; /*信号量的值*/
Unshort sempid; /*记录对信号量最后一次实施操作进程的 PID*/
}

PV 操作
(为了解决死锁)IPC 信号量机制引进了信号量集合的概念,可以使用原语一次对多个信号量进行操作。

2.信号量集合

信号量集合:把进程需要访问资源对应的信号量组成一个信号量集合,并可以使用操作原语一次性地对信号量集中的多个信号量进行 PV 操作。
信号量数组:在 IPC 信号量机制中把多个信号量组成一个信号量集合,该集合由信号量结构体 sem组成,称为信号量数组。
信号量集合描述符:系统中的每个信号量集合用一个描述符描述其特征和记载其管理信息。其定义如下:

Struct semid_ds
{
Struct_ipc_perm sem_perm; /*对信号量集合的访问权限*/
Time_t sem_otime; /*最后一次对信号量集进行操作的时间*/
Time_t sem_ctime; /*最后一次修改信号量集的时间*/
Struct sem *sem_base; /*指向信号量数组*/
Struct sem_queue *sem_pending; /*指向等待队列头*/
Struct sem_queue *sem_pending_last;/* 指向等待队列尾*/
Struct sem_undo *undo; /*进程终止时需要使用 sem_undo 结构体中的信息,对信号量集合进行有关操作*/
Unshort sem_nsems; /*信号量集合中信号量的数目*/
}
3.信号量集合的集中

IPC 对系统中的所有信号量集合进行集中管理,把所有的信号量集合描述符组织在一个 semary[]数组中,其定义如下:

Static struct semid_ds *smeary[SEMMNI];

其中 SEMMNI 为数组大小,是系统中可以设置的信号量集合的最大数目,其缺省值为 128,宏定义如下:

#define SEMMNI 128

4.7.2 信号量集合的创建和检索

1.semget()
系统为每个信号量集合设定了一个唯一的标识号 ID,IPC 提供了创建信号量结合和获取信号量集合标识号的系统调用 semget(),其原型定义如下:

Int semget(key_t key, int nsems, int semflg);

该系统调用正常则返回值为信号量集合的标识号,出错则返回负数。
Key:要创建或要获取的信号量集合的标志键值,可以用户指定,也可使用符号常量 IPC_PRIVATE 由系统给定。
Nsems:指出要创建的信号量集合中包含的信号量的个数。
Semflgs:操作标志;指定了信号量集合的访问权限和操作模式。其取值或符号常量及意义如下:
0400 允许创建者读
0200 允许创建者写
0040 允许创建者同组用户读
0020 允许创建者同组用户写
0004 允许其它所有的进程读
0002 允许其它所有的进程写
IPC_CREAT(00001000) 创建新的信号量集合
IPC_EXCL(00002000) 检索信号量集合

前六项指定了信号量集合的访问权限,后两项指定了操作模式。访问权限和操作模式可以使用逻 辑与(|)组合在一起表示复合属性。

2.创建信号量集
若操作模式设定为 IPC_CREAT:

则当系统中尚没有建立与 key 对应的信号量集合,则建立这个新的集合,并返回新集合的标 识号;
当系统中已经存在与键值 key 对应的信号量集合,则返回这个集合的标识号;
当不能创建,则返回-1

若操作模式设定为 IPC_CREAT|IPC_EXCL:

与前不同的是,当系统中已经存在与键值 key 对应的信号量集合,则返回错误值-EEXIST。

例:建立一个健值为 KEY,包含 1 个信号量,允许任何进程读写的信号量集合时,调用函数的形式为: id=semget(KEY,1,0666|IPC_CREAT);
3.检索信号量集 检索信号量集
检索一个信号量集合的标识号时,只需将 semflg 中的操作模式设为 IPC_EXCL。若存在,返回集合的标识号,否则,返回-1;

4.7.3 信号量 PV 操作

IPC 中没有对信号量分别设置 P 和 V 操作原语,而是统一由具有原语性质的系统调用 semop()实现的,通常称其为信号量操作函数。其定义如下:

Int semop(int semid,struct sembuf *sops, unsigned nsops);
//Semid:实施 pv 操作的信号量集合的标识号
//Nsops:本次实施操作的信号量的个数
//Sops:指向一个信号量操作数组。因为每次对信号量集合中实施操作的信号量个数不同,不同信号量实施的操作不同,所以必须指明本次操作是对哪些信号量,实施哪些操作。该数组的元素个数就是 Nsops。
Sops 中的每个元素是一个 sembuf 结构体,它由系统定义:
Struct sembuf
{
Ushort sem_num; /*指出信号量在信号量数组中的下标*/
Short sem_op; /*指出操作的种类*/
Short sem_flg; /*指出操作的标志*/
}

说明:

Sem_op 的值决定操作的类型:
1、Sem_op 的值是负数:表示进程请求资源,则实施 P 操作,把 semval 的值减去 sem_op绝对值。
2、Sem_op 的值是正数:表示进程释放资源,则实施 V 操作,把 semval 的值加上 sem_op以上两种情况下,若对信号量集实施操作后,所有信号量的值 semval 均大于等于 0,则函数返回 0,表示进程所需的多个资源都可用,此时进程可以继续运行;否则,只要有一个 semval结果为负数,则表示进程需要的这种资源不可用,进程被阻塞,并将本次操作加入该信号量集合的等待队列。
3、Sem_op 的值为 0。此时若 semval 也是 0,则函数返回,调用 semop 的进程继续执行;若semval 非 0,则进程被阻塞。
4、sem_flg:控制进程的执行。通常取值 0;若指定为 IPC_NOWAIT,则在执行 semop操作时,即使出现需要进程阻塞的情况,也不阻塞,而是继续运行。

4.7.4 信号量操作等待队列

1.信号量操作等待队列

IPC每个信号量集合都有一个等待队列,分别由其描述符中的成员向 sem_pending 和 sem_pending_last 指向其头部和尾部。该等待队列是由 sem_queue 结构体组成的双向循环链表。Sem_queue 结构体定义如下:

Struct sem_queue
{
Struct sem_queue *next; /*指向队列后一个节点*/
Struct sem_queue *prev; /*指向队列前一个节点*/
Struct wait_queue *sleeper; /*指向被阻塞进程*/
Struct sem_undo *undo;
Int pid; /*实施操作的进程的 PID*/
Int status;
Struct semid_ds *sma; /*指出对哪个信号量集合实施操作*/
Struct sembuf *sops; /*指向是进程阻塞的操作数组*/
Int nsops; /*指出操作数组中操作的个数*/
}
2.将信号量操作移出等待队列

若某个进程在执行 semop()时没有阻塞,函数将检查该信号量集的操作等待队列:

1、若无操作等待, 则返回;
2、若有操作等待, 则依次重新执行这些操作:
1)若进程仍需等待,则操作保留在等待队列中;
2)若进程可以继续执行,则通过该 sem_queue 结构体中的 sleeper 在进程等待队列中找到该进程,并将其唤醒;再将该sem_queue 结构体从操作等待队列中删除。

4.7.5 信号量控制操作

IPC 信号量机制提供了可以对信号量集合进行多种控制操作的系统调用 semctl(),它能实现对信号量的初始化、查询、修改、删除等功能。

Int semctl(int semid,int semnum,int cmd,union semun arg);
Semid:指向操作对象,即信号量集合标记号。
Semnum:信号量的索引号,指明信号量在信号量数组中的下标。
Cmd:指定各种不同操作。
Arg:用于传递执行各种控制操作时所需的参数。
union semun 是 IPC 定义 的一个联合体。其定义 :

Union semum
{
Int val;
Struct semid_ds *buf;
Unshort *array;
Struct seminfo *_buf;
Void*_pad;
}

cmd,对应的符号常量和意义所在:

符号常量意义
IPC_STAT读取信号量集合 semid_ds 结构体的内容,并把它写进参数 arg 给出的 semnum 联合体中成员项 buf 指定的 semid_ds 结构中。此时无视参数 Semnum。
IPC_SET修改信号量集合 semid_ds 结构体的成员项 sem_perm 结构中的某些成员项的值;同时sem_ctime 被自动更新。只有信号量集合创建者、同组用户和超级用户可以执行该操作。修改值取自参数 arg给出的 semun 联合体中 buf 指定的 semid_ds 结构体的第一个成员项。
IPC_RMID从内核中删除信号量集合。只有信号量集合创建者和超级用户。在该信号量集合中等该信号量操作的所有进程被唤醒,并得到错误信息 EIDRM。
GETPID获取信号量数组中以参数 semnum 做为索引值指定信号量的 sempid 值。它是对信号量最后一个执行 semop()操作的进程的 PID。
SETVAL设置信号量数组中以参数 semnum 做为索引值指定信号量的值。Arg 的 semun 联合体成员项 val 中给出要设置的值。
GETVAL获取信号量数组中以参数 semnum 做为索引值指定信号量的 semval 值。其值写入 arg 的semun 联合体成员项 val 中。该值也作为函数返回值返回。
SETALL设置信号量集合中所有信号量的值,设置值存放在 Arg 的 semun 联合体成员项 array 中。
GETALL获取信号量集合中所有信号量的值,并存放在 Arg 的 semun 联合体成员项 array 中。
GETNCNT得到等待以 semnum 为索引指出的信号量的值为非 0 的进程的个数。

4.7.6 信号量的程序例

程序例 1:创建一个信号量集合,并对信号量进行 P 操作。
/*mksem.c*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
Int main(void{
Int semid; /*信号量集合标识号*/
Int nsems=1; /*信号量集合中信号量的个数*/
Int flags =6/*对信号量集合的访问权限,允许所有进程进行读写*/
Struct sembuf buf;/*信号量操作数组*/
/*创建信号量集*/
Semid = semget(IPC_PRIVATE,nsems,flags);
If(semid<0) /*若返回值为负,则出错*/
{
Printf(“semapher ceate failer! \n”); 
Exit(EXIT_FAILURE)}
Printf(“semapher ceated:%d\n”,semid); 
/*设置操作数组个成员项的值*/
Buf.sem_num=0; /*下标为 0,因为只有一个信号量*/
Buf.sem_op =1; /*信号量加 1 操作*/
Buf.sem_flg=IPC_NOWAIT; /*进程不阻塞*/
If((semop(semid,&buf, nsems)<0/*执行信号量操作*/
{
/*信号量操作失败*/
Printf(“semapher operation failer! \n”); 
Exit(EXIT_FAILURE)}
System(“ipcs –s”); /*执行键盘命令 ipcs –s,显示 IPC 信号量*/
Exit(EXIT_SUCCESS)/*成功退出*/
}

程序运行结果如下:

$./mksem
semapher ceated:520
-----semapher arrays------
Key semid owner perms nsems status
0x00000000 520 wang 666 1
程序例 2:通过信号量控制函数删除信号量集合。
/*sctlsem.c*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
Int main(int argc,char *argv[ ]{
Int semid; /*信号量集合标识号*/
If(argc!=2{
Puts(“USAGE:sctl<semaphore id>”);
exit(EXIT_FAILURE)}
Semid=atoi(argv[1]); /*从命令行参数得到信号量集合标识号*/
/*删除信号量集合*/
If((semctl(semid,0IPC_RMID))<0/*调用信号量控制函数*/
{
/*返回负值,失败退出*/
Printf(“semapher control failer! \n”); 
exit(EXIT_FAILURE)}
Else
{
Puts(“semapher removed! ”);
System(“ipcs –s”); /*执行键盘命令 ipcs –s,显示 IPC 信号量*/
}
Exit(EXIT_SUCCESS)/*成功退出*/
}

程序运行时,需要给出所要删除的信号量集合的标识号,程序运行结果如下:

$./ sctlsem.c 520
semapher removed!

这篇关于<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 7》(11)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/432143

相关文章

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

Linux使用nohup命令在后台运行脚本

《Linux使用nohup命令在后台运行脚本》在Linux或类Unix系统中,后台运行脚本是一项非常实用的技能,尤其适用于需要长时间运行的任务或服务,本文我们来看看如何使用nohup命令在后台... 目录nohup 命令简介基本用法输出重定向& 符号的作用后台进程的特点注意事项实际应用场景长时间运行的任务服

什么是cron? Linux系统下Cron定时任务使用指南

《什么是cron?Linux系统下Cron定时任务使用指南》在日常的Linux系统管理和维护中,定时执行任务是非常常见的需求,你可能需要每天执行备份任务、清理系统日志或运行特定的脚本,而不想每天... 在管理 linux 服务器的过程中,总有一些任务需要我们定期或重复执行。就比如备份任务,通常会选在服务器资

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

IDEA中的Kafka管理神器详解

《IDEA中的Kafka管理神器详解》这款基于IDEA插件实现的Kafka管理工具,能够在本地IDE环境中直接运行,简化了设置流程,为开发者提供了更加紧密集成、高效且直观的Kafka操作体验... 目录免安装:IDEA中的Kafka管理神器!简介安装必要的插件创建 Kafka 连接第一步:创建连接第二步:选