钦州教育论坛网站建设wordpress 语言插件

当前位置: 首页 > news >正文

钦州教育论坛网站建设,wordpress 语言插件,知乎网站内容建设的逻辑,好看的网站首页system V一、system V介绍二 、共享内存2.1 共享内存的原理2.2 共享内存接口2.2.1 创建共享内存shmget2.2.2 查看IPC资源2.2.3 共享内存的控制shmctl2.2.4 共享内存的关联shmat2.2.5 共享内存的去关联shmdt2.3 进程间通信2.4 共享内存的特性2.5 共享内存的大小三、消息队列3.1 … system V一、system V介绍二 、共享内存2.1 共享内存的原理2.2 共享内存接口2.2.1 创建共享内存shmget2.2.2 查看IPC资源2.2.3 共享内存的控制shmctl2.2.4 共享内存的关联shmat2.2.5 共享内存的去关联shmdt2.3 进程间通信2.4 共享内存的特性2.5 共享内存的大小三、消息队列3.1 消息队列的概念3.2 消息队列接口3.2.1 消息队列的获取msgget3.2.2 消息队列的控制msgctl3.2.3 消息队列发送数据msgsnd3.2.4 消息队列获取msgrcv四、信号量4.1 信号量概念4.2 信号量的用处4.3 信号量的pv操作4.4 信号量接口4.4.1 信号量申请semget4.4.2 信号量控制semctl4.4.3 信号量操作semop五、总结一、system V介绍 进程间通信除了通过管道都是基于文件的通信方式还有一种方式是SystemV标准的进程间通信方式。SystemV是一个在OS层面专门为进程通信设计的一个方案。这些都是由计算机科学家和程序员设计的并且需要给用户使用。 如果要给用户用是以什么方式给用户使用的呢在操作系统层面上SystemV是OS内核的一部分是为OS中多进程提供的一种通信方案。但是OS不相信任何用户给用户提供功能的时候采用系统调用。所以System V进程间通信一定会存在专门用来通信的接口system call。 因为在早期由很多的方案但是我们需要统一使用一个方案所以现在诞生了在统一主机内的进程间通信方案system V方案。 system V IPC提供的通信方式有三种 共享内存、消息队列、信号量 二 、共享内存 2.1 共享内存的原理 前面说过两个进程要通信就需要看到同一块资源。 而我们知道进程之间具有独立性物理内存当中代码和数据也互相独立。 那么现在我们可以在物理内存中创建一个内存块让不同的进程都能看到这个内存块具体的做法如下 1️⃣ 通过某种调用在内存中创建一份内存空间。 2️⃣ 通过某种调用让进程”挂接“到这份内存空间上。将创建好的内存映射进进程地址空间 在后面可能不会共享内存了。所以在不用共享内存的时候 3️⃣ 去关联去挂接。 4️⃣ 释放共享内存。 对于共享内存的理解 OS内可能存在多个进程同时使用不同的共享内存来进行进程间通信既然有多份共享内存那么操作系统就要管理它们按照前面学习的经验先描述后组织描述就是对共享内存的一系列属性进行描述而后用数据结构组织起来这样对共享内存的管理变成了对数据结构的操作。 2.2 共享内存接口 2.2.1 创建共享内存shmget shmget用来创建共享内存 #include sys/ipc.h#include sys/shm.hint shmget(key_t key, size_t size, int shmflg);RETURN VALUEOn success, a valid shared memory identifier is returned. On errir, -1 is returned, and errno is set to indicate the error.参数说明 size共享内存的大小。 shmflag通常有两种选项IPC_CREAT、IPC_EXCL。 IPC_CREAT 共享内存如果不存在则创建不存在则获取。 IPC_EXCL 无法单独使用 IPC_CREAT | IPC_EXCL 如果不存在就创建如果存在就出错返回保证共享内存是新创建的。 如果shmflag是0默认就是IPC_CREAT。 key保证看到同一份共享内存能进行唯一性标识就像省份证号码一样数字不重要只用来标识唯一性。通过ftok函数转化。 如果创建成功返回共享内存的标识符如果失败则返回-1。 ftok用来形成key #include sys/types.h #include sys/ipc.hkey_t ftok(const char *pathname, int proj_id); RETURN VALUE On success, the generated key_t value is returned.
On failure -1 is returned, with errno indicating the error as for the stat(2) system call.ftok第一个参数是自定义路径名第二个参数是自定义的项目ID。最后唯一的共享内存ID就是通过路径名项目ID来标识。最后生成的返回值并不重要只要它能生成一个值来唯一标识这块共享内存就可以。 只要参数不变生成的返回值就不会变。 这样就可以让两个进程拥有同一个key就可以用key找到同一份共享内存。 key_t GetKey() {key_t n ftok(PATHNAME, PROJ_ID);if(n -1){std::cerr errno : strerror(errno) std::endl;assert(false);}return n; }int Creatshm(key_t key) {int shmid shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);if(shmid -1){std::cerr errno : strerror(errno) std::endl;assert(false);}return shmid; }int Getshm(key_t key) {int shmid shmget(key, SIZE, IPC_CREAT | 0666);if(shmid -1){std::cerr errno : strerror(errno) std::endl;assert(false);}return shmid; }key的理解 上面也说过了OS会把内存块管理起来共享内存物理内存块共享内存的相关属性。描述共享内存时就有一个字段struct shm中有key。 一个进程创建内存块后把key值写进相关属性中而另一个进程拿着key值遍历相关属性查找。这样就完成了两个进程共享一块内存块。 我们发现key和shmid都是标识内存块的key是在内核标识唯一性而shmid是在用户层标识唯一性这样即使操作系统有什么变化也不会影响用户使用充分的解耦。他们的关系就类似于fd与inode。 2.2.2 查看IPC资源 共享内存的生命周期不是随着进程的而是随着OS的这也是所有system V进程间通信的特征。 ipcs -m 查看共享内存 ipcs -q 查看消息队列 ipcs -s 查看信号量
ipcs 三个一起查看 ipcrm -m shmid 删除共享内存
2.2.3 共享内存的控制shmctl shmctl控制共享内存 #include sys/ipc.h #include sys/shm.hint shmctl(int shmid, int cmd, struct shmid_ds *buf);它的作用是对共享内存的控制。 参数介绍 shmid控制共享内存的标识符。 cmd控制的种类主要用的是IPC_RMID立即移除共享内存。 buf控制共享内存的数据结构设置为空即可。 返回值0表示返回成功-1表示失败。 void Delshm(int shmid) {if(shmctl(shmid, IPC_RMID, nullptr) -1){std::cerr errno : strerror(errno) std::endl;assert(false);} }2.2.4 共享内存的关联shmat #include sys/types.h #include sys/shm.hvoid *shmat(int shmid, const void shmaddr, int shmflg);参数介绍 shmaddr可以指定虚拟内存设置为nullptr即可。 shmflg读取权限默认为0。 返回值返回共享内存的起始地址。 void Attachshm(int shmid) {void* mem shmat(shmid, nullptr, 0);if((long long)mem -1L)// 64位指针8字节{std::cerr errno : strerror(errno) std::endl;assert(false);}return mem; }2.2.5 共享内存的去关联shmdt 去关联是指把进程和共享内存之间的映射关系删掉修改页表并不是删除共享内存。 #include sys/types.h #include sys/shm.hint shmdt(const void shmaddr);它的参数就是在shmat返回的参数。 成功返回0失败返回-1。 void Detachshm(void start) {if(shmdt(start) -1){std::cerr errno : strerror(errno) std::endl;assert(false);} }2.3 进程间通信 comm.hpp #ifndef _COMMHPP #define _COMMHPP#include iostream #include sys/types.h #include sys/ipc.h #include sys/shm.h #include cstring #include cerrno #include cassert #include cstdlib #include cstdio #include unistd.h#define PATHNAME .. #define PROJ_ID 12345 #define SIZE 4096key_t GetKey() {key_t n ftok(PATHNAME, PROJ_ID);if(n -1){std::cerr errno : strerror(errno) std::endl;assert(false);}return n; }int Creatshm(key_t key) {int shmid shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);if(shmid -1){std::cerr errno : strerror(errno) std::endl;assert(false);}return shmid; }int Getshm(key_t key) {int shmid shmget(key, SIZE, IPC_CREAT | 0666);if(shmid -1){std::cerr errno : strerror(errno) std::endl;assert(false);}return shmid; }void Delshm(int shmid) {if(shmctl(shmid, IPC_RMID, nullptr) -1){std::cerr errno : strerror(errno) std::endl;assert(false);} }void* Attachshm(int shmid) {void* mem shmat(shmid, nullptr, 0);if((long long)mem -1L)// 64位指针8字节{std::cerr errno : strerror(errno) std::endl;assert(false);}return mem; }void Detachshm(void* start) {if(shmdt(start) -1){std::cerr errno : strerror(errno) std::endl;assert(false);} }#endifshm_a.cc #include comm.hppint main() {key_t k GetKey();// 创建共享内存int shmid Creatshm(k);// 挂接char* start (char)Attachshm(shmid);//使用while(true){if(strlen(start) 4){printf(%s\n, start);}if(strlen(start) 4){break;}sleep(1);}// 去关联Detachshm(start);// 删除共享内存Delshm(shmid);return 0; }shm_b.cc #include comm.hppint main() {key_t k GetKey();// 获取共享内存int shmid Getshm(k);// 挂接char start (char*)Attachshm(shmid);// 使用std::string str hello shm;int cnt 0;while(cnt ! 8){snprintf(start, SIZE, %s[%d], str.c_str(), cnt);cnt;sleep(1);}std::string cmd stop;snprintf(start, SIZE, %s, cmd.c_str());// 去关联Detachshm(start);return 0; }2.4 共享内存的特性 1️⃣ 共享内存是所有的进程间通信速度最快的。优点 2️⃣ 共享内存不提供任何同步或者互斥机制不提供不代表不需要所以需要程序员自行保证数据的安全这也造成了共享内存在多进程中是不太安全的。缺点 3️⃣ 共享内存的生命周期是随OS的而不是随进程的这是所有System V进程间通信的共性。 为什么速度快呢 管道和共享内存考虑键盘输入和显示器输出对于同一份数据共享内存有几次数据拷贝管道有几次数据拷贝 管道 可以看到写到管道需要拷贝两次而另一个进程读也需要两次所以一共四次。如果考虑到输入输出外设那么就是六次。 共享内存 直接写入共享内存直接从共享内存输出所以是两次。考虑到输入输出的话就是四次。 2.5 共享内存的大小 这里讲的是shget的第二个参数一般建议设置成40964KB的整数倍因为系统分享内存是以4KB为单位假如我们申请的是4097那么系统就会直接向上取整也就是4096*2但是我们只能使用其中的4097大小。 三、消息队列 3.1 消息队列的概念 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法读端和写端公用一个队列每个数据块就是队列的一个节点每个数据块都会有个记录类型的数据来判断该数据块该被哪个进程读取。 3.2 消息队列接口 3.2.1 消息队列的获取msgget #include sys/types.h #include sys/ipc.h #include sys/msg.hint msgget(key_t key, int msgflg);这里的msgflg跟共享内存的两个参数一摸一样IPC_CREAT、IPC_EXCL。 返回值msgget函数返回的一个有效的消息队列标识符 3.2.2 消息队列的控制msgctl #include sys/types.h #include sys/ipc.h #include sys/msg.hint msgctl(int msqid, int cmd, struct msqid_ds *buf);参数说明 msqid消息队列的标识符。 其他的参数跟shmctl一样。 3.2.3 消息队列发送数据msgsnd #include sys/types.h #include sys/ipc.h #include sys/msg.h int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);参数说明 msqid消息队列的用户级标识符。 msgp表示待发送的数据块输出型参数。
msgsz表示所发送数据块的大小 msgflg表示发送数据块的方式一般默认为0即可 成功返回0失败返回-1 3.2.4 消息队列获取msgrcv #include sys/types.h #include sys/ipc.h #include sys/msg.h ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg)参数跟上面msgsnd一致。 四、信号量 4.1 信号量概念 信号量本质上就是个计数器它统计的是公共资源资源还剩多少。 公共资源可以被多个进程同时访问的资源而如果访问没有被保护的公共资源就会导致数据不一致问题一个进程还在写的时候另一个进程就开始读。所以公共资源需要保护被保护起来的资源称为临界资源。而访问这些临界资源的那部分代码称为临界区。其他的代码就称为非临界区。 保护公共资源同步和互斥 互斥当有多个进程想要访问同一份资源的时候我们只允许一个进程访问当这个进程访问完了下一个进程才能访问。 原子性要么不做要么做完只有这两种状态的情况。 既然我们想让多个进程看到同一个计数器那么信号量也是个公共资源。 4.2 信号量的用处 举个例子假设我们要去看电影而里面的座位只有我们买了票才能拥有这里的票就是信号量我们买了一张后信号量就–。 所以当我们想要某种资源的时候我们可以进行预定买票成功。 共享资源可以作为一个整体使用或者划分成多个子资源部分。大部分都是整体使用比如果管道。 如果我们申请成功相当于我们预定了共享内存中的一小部分资源。如果不成功就不能访问共享资源以达到保护其他进程的目的。 在访问公共资源前要先申请信号量而信号量本身就是个公共资源那么信号量也带保护自己的安全。那么如何保证呢 4.3 信号量的pv操作 信号量操作本质上就是计数器的或者–是原子性的。当我们预定资源的时候–称为p操作释放资源称为v操作。 如果信号量的初始值是1就代表了访问公共资源作为一个整体来使用一个进程申请了别的进程就不能再申请了我们把只有两种状态的信号量称为二元信号量。 4.4 信号量接口 4.4.1 信号量申请semget #include sys/types.h #include sys/ipc.h #include sys/sem.hint semget(key_t key, int nsems, int semflg);参数介绍 nsems表示申请信号量的个数 第一个和第三个参数就跟前面的shmget相同。 返回值信号量集创建成功时semget函数返回的一个有效的信号量集标识符 4.4.2 信号量控制semctl #include sys/types.h #include sys/ipc.h #include sys/sem.h int semctl(int semid, int semnum, int cmd, …);参数介绍 semid信号量标识符 semnum信号量的下标默认0 4.4.3 信号量操作semop #include sys/types.h #include sys/ipc.h #include sys/sem.h int semop(int semid, struct sembuf sops, unsigned nsops);参数介绍 sembuf一个结构体 sem_num信号量下标。 sem_op1表示p操作-1表示–v操作。 sem_flg选项设为0即可。 nsops有多少个sembuf结构体。 五、总结 我们可以发现共享内存、消息队列、信号量接口相似度非常高尤其是获取与删除这些都是system V标准的进程间通信。 他们的第一个成员都是ipc_perm struct ipc_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 /unsigned short mode; / Permissions SHM_DEST andSHM_LOCKED flags /unsigned short __seq; / Sequence number */};我们可能会申请共享内存、消息队列、信号量的任意一种那么操作系统如何组织它们呢 因为ipc_perm是一样的所以可以维护一个struct ipc_perm*的指针数组存共享内存、消息队列、信号量它们的第一个元素的地址也就是ipc_perm。 而我们知道结构体的第一个成员的地址和结构体对象的地址在数字上是相等的。 所以当我们想使用的时候直接强转成想用的结构体共享内存、消息队列、信号量就可以。