当前位置: 首页> 汽车> 车展 > 简单好看的logo图片_电商定制开发_百度网站名称和网址_企业管理培训课程费用

简单好看的logo图片_电商定制开发_百度网站名称和网址_企业管理培训课程费用

时间:2025/7/13 21:49:16来源:https://blog.csdn.net/m0_74207969/article/details/144940005 浏览次数: 0次
简单好看的logo图片_电商定制开发_百度网站名称和网址_企业管理培训课程费用

目录

1.信号量概念

2.临界资源与临界区

3.信号量原理

4.原子性

5.System V信号量接口

创建信号量集合

控制信号量集合

6.底层如何看待IPC资源


1.信号量概念

        信号量是一种用于进程间同步和互斥的机制。它本质上是一个计数器,用于控制多个进程对共享资源的访问。可以把信号量想象成是一个资源的 “许可证” 发放器,进程需要获取这个 “许可证” 才能访问共享资源。

        进程之间通信的基础条件是多个进程能够看到同一份资源,但是在访问的时候如果是并发访问的话,就极大概率上会出现数据不一致的问题,也就是说一个进程还没有将内容全部写入,另一个进程就读取并基于该数据进行执行了。所以这种被共同访问的资源需要被保护起来,那么就会使用互斥和同步的策略。

        对于共享内存来说,是由我们用户自己去维护共享内存区域的互斥与同步机制,而对于管道和消息队列则是操作系统帮助我们进行维护的。

2.临界资源与临界区

        对于上述我们所说的需要被保护起来的资源称为临界资源,访问该临界资源的代码称为临界区。那么也就是说想要维护临界资源的话,维护临界区就可以了。

3.信号量原理

        那么该如何保护呢?有很多种方法,这里我们讲述信号量的方法。信号量其实就是一个计数器,记录着该临界资源同一时间有多少执行流可以进行访问,每一个执行流想要访问该临界资源时,要先申请信号量,本质也就是对信号量进行减1的操作,如果信号量不为0就可以申请,为0的话,执行流就会申请失败,然后被挂起阻塞等待信号量资源。释放信号量的时候,就是对信号量进行加1的操作。

// 单个信号量可以简单理解为该结构

struct sem

{

        int count;                                // 计数器

        task_struct *wait_queue;       // 等待队列

}

        访问临界资源其实一定是通过代码访问的,所以在访问临界资源之前添加申请信号量的代码,结束访问的时候,添加释放信号量的代码就实现了对于临界资源的保护操作。

4.原子性

        那么我们会发现一个问题,信号量是用来保护临界资源的,如果多个进程想要同时访问临界资源就必须去申请信号量,那么就相当于多个资源同时申请信号量了,信号量也是一个资源啊,那么他并发访问不会出问题吗。因为信号量是用来保护临界资源的,所以把信号量设置为了原子操作。

        CPU在执行程序的时候,虽然有各种调度机制,有并发同步执行,但是最终同一时间只会执行一条指令(代码在最终都会转化为一条一条的二进制指令),原子性操作就是一个操作在底层只会转化为一条指令,CPU的执行是以指令为单位的,对于一条指令,不会分开执行,会一下执行完毕。所以虽然有很多执行流同时申请信号量,在底层转化为了很多个申请信号量的指令,但是CPU在执行完一条之后,也就是说有一个执行流申请到信号量之后,信号量的计数就会减少到0,其他指令再在CPU上执行的时候,就会发现没有信号量了,就会挂起到等待队列中,等待信号量资源。

5.System V信号量接口

创建信号量集合

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

        该接口用于创建或获取一个System V信号量集合,如果成功返回一个非负整数,表示整个信号量集合的标识符semid,失败返回-1,错误码被设置。nsems表示信号量集合中信号量的个数,如果是获取一个已经存在的信号量集合,可以设置为0。semflg用于指定信号量集合的创建权限和其他属性,该字段的参数和共享内存一致。

创建一个信号量的代码:

// 1. 使用ftok函数生成一个唯一的键值,用于标识信号量
key_t key = ftok(".", 'a');
if (key == -1)
{perror("ftok");return 1;
}// 2. 使用semget函数创建一个信号量集合,这里只创建包含1个信号量的集合
// IPC_CREAT表示如果不存在则创建,0666表示权限设置,类似文件权限
int semid = semget(key, 1, IPC_CREAT | 0666);
if (semid == -1)
{perror("semget");return 1;
}
控制信号量集合

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

        用于控制信号量集合,如获取信号量集合的状态信息、修改其属性或者标记它为删除。semid是唯一标识一个信号量集合的标识符,也最好使用ftok函数进行生成。semnum表示哟啊操作的信号量在信号量集合的编号,如果cmd命令是针对整个信号量集合的操作,那么这个参数可以忽略设置为0。cmd则是一个命令码, 用于指定要对信号量集合执行的操作类型。可变参数则是根据cmd的不同传递不同参数。

        cmd字段:IPC_STAT、IPC_SET、IPC_RMID这三个参数和共享内存一样。GETVAL用于获取指定的信号量,对于修改和获取等操作,往往都需要传递一个union semun枚举类型用来修改或者接收信号量。

union semun

{

        int val;

        struct semid_ds *buf;

        unsigned short *array;

        struct seminfo *__buf;

};

        对于一般场景来说,用不上semnum,对于复杂场景下,可能一个信号量集合中不同信号量用于控制不同的共享资源或者不同的同步机制。

初始化信号量:

// 定义semun联合体,用于semctl函数的参数传递,不同操作系统可能有细微差异
union semun {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;
};// 初始化刚创建的单个信号量的值,这里将其初始化为1,可根据实际需求调整
union semun arg;
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) == -1) 
{perror("semctl SETVAL");return 1;
}

删除信号量:

// 删除信号量集合,使用IPC_RMID命令
if (semctl(semid, 0, IPC_RMID, NULL) == -1) 
{perror("semctl IPC_RMID");return 1;
}

6.底层如何看待IPC资源

        对于System V系列的共享内存、小心队列以及信号量集合在底层来说都是一个个结构体,方便操作系统对于这些IPC资源,因为有三种机制,所以要维护三个队列吗,其实并不是这样的。在底层这三种IPC的数据结构都是struct xxxid_ds,他们的第一个参数都是struct ipc_prem。这样的话操作系统维护一个队列就可以了。

struct ipc_id_ary

{

        int size;     // 存放IPC资源的个数

        struct Kern_ipc_perm* p[0];   // 存放各个IPC资源的指针数组

};

         操作系统内部维护一个ipc_id_ary结构体对象,内部存放一个size参数记录创建的IPC资源的个数,也就是kern_ipc_perm柔性数组的元素个数,这三种不同的IPC资源的第一个字段都是存放的kern_ipc_perm,柔性数组的元素指向并不是IPC资源结构体,而是指向的每个IPC资源结构体的第一个参数,然后第一个参数里面记录的是什么类型的IPC资源,那么通过访问第一个参数就可以直到该IPC资源是什么类型的了。同时第一个参数的地址也就是该IPC资源的首地址,通过强转的方式就可以得到IPC资源结构体的地址了。

(shm_perm*)p[i]

关键字:简单好看的logo图片_电商定制开发_百度网站名称和网址_企业管理培训课程费用

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: