淘客网站怎么做啊,南京科技网站设计多少钱,自己制作一个网页,asp网站开发教案共享内存是分配一块能被其他进程访问的内存。每个共享内存段在内核中维护一个内部数据结构shmid_ds(和消息队列、信号量一样)#xff0c;该结构定义在头文件linux/shm.h中,这是我从源码里抄的
#includelinux/shm.h
struct shmid_ds {struct ipc_perm shm_perm; /* 操…共享内存是分配一块能被其他进程访问的内存。每个共享内存段在内核中维护一个内部数据结构shmid_ds(和消息队列、信号量一样)该结构定义在头文件linux/shm.h中,这是我从源码里抄的
#includelinux/shm.h
struct shmid_ds {struct ipc_perm shm_perm; /* 操作许可 */int shm_segsz; /* size of segment (bytes) */__kernel_old_time_t shm_atime; /* 最后一个进程访问共享内存的时间 */__kernel_old_time_t shm_dtime; /* 最后一个进程离开共享内存的时间 */__kernel_old_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* 当前使用该共享内存段的进程数量 */unsigned short shm_unused; /* compatibility */void *shm_unused2; /* ditto - used by DIPC */void *shm_unused3; /* unused */
};
但是总结了上一节的经验我发现sys/shm.h也同样定义了该结构体所以真正编写代码时可能只用包含sys/shm.h头文件
共享内存的创建与操作
共享内存区的创建
Linux下使用函数shmget来创建一个共享内存区或者访问一个已经存在的共享内存区。该函数定义在头文件linux/shm.h中
但是根据我自己的linux来看linux/shm.h并没有该函数在sys/shm.h中定义了该函数所以以事实为准认为该函数定义在sys/shm.h中。
并且根据实践linux/shm.h和sys/shm.h同时包含的话编译不给过所以下面就只用sys/shm.h了
#include sys/shm.hint shmget(key_t key, size_t size, int shmflg); key用于标识共享内存段的关键字。size要创建的共享内存段的大小以字节为单位。shmflg用于指定创建共享内存段的访问权限和其他标志位。 返回值 如果成功返回一个非负整数该整数是共享内存段的标识符即共享内存的ID。如果失败返回 -1并设置 errno 来指示错误的原因。 该函数用法与消息队列和信号量集的创建一样。key一般通过ftok得到shmflg的话一般是IPC_CREATE或者IPC_EXCL|IPC_CREATE 再加上权限的组合。具体含义请到消息队列的那一节查看《Linux C编程实战》笔记消息队列-CSDN博客
如果是创建的话size要大于0如果只是访问size置为0.
共享内存区的操作
在使用共享内存区之前必须通过shmat函数将其附加到进程的地址空间。进程与共享进程就建立了连接。shmat调用成功后就会返回一个指向共享内存区的指针使用该指针就可以访问共享内存区了如果失败返回-1.该函数定义在sys/shm.h中这也是我根据实际改的书上还是说是linux/shm.h
#include sys/shm.hvoid *shmat(int shmid, const void *shmaddr, int shmflg); shmid要连接的共享内存段的标识符由 shmget 函数返回的ID。shmaddr指定共享内存连接到进程地址空间的起始地址通常设置为 NULL让系统自动选择一个合适的地址。shmflg用于指定连接共享内存的选项通常为0。 返回值 如果成功返回一个指向共享内存段第一个字节的指针。如果失败返回 (void *) -1并设置 errno 来指示错误的原因。 当进程结束时使用共享内存区时要通过函数shmdt断开与共享区内存的连接。该函数声明在sys/shm.h
#include sys/shm.hint shmdt(const void *shmaddr);
参数shmaddr为shmget的返回值。该函数调用成功后返回0否则返回-1.进程脱离共享内存区后数据结构shmid_ds中的shm_nattch就会减1.但是共享内存段依然存在只有shm_nattch为0后即没有任何进程再使用该共享内存区共享内存区才应该在内核中被删除。一般来说一个进程终止时他所附加的共享内存区都会自动脱离。
共享内存区的控制
#include sys/shm.hint shmctl(int shmid, int cmd, struct shmid_ds *buf); shmid 是共享内存区的标识符通常由 shmget 函数返回。cmd 是要执行的操作可以是各种控制命令之一。buf 是一个指向 shmid_ds 结构的指针用于传递或获取与共享内存相关的信息。 常用的控制命令包括 IPC_STAT获取共享内存区的状态信息并将其存储在 buf 中。IPC_SET设置共享内存区的状态信息buf 中包含了要设置的信息。IPC_RMID删除共享内存区。 如果你想删除共享内存区可以将 cmd 参数设置为 IPC_RMID并将共享内存区的标识符 shmid 作为 shmctl 函数buf设置为NULL。 示例程序
本例通过读写者问题不考虑优先级来演示共享内存和呃呃信号量如何配合使用。这里的读者写者问题要求一个进程读共享内存的时候其他进程不能写内存当一个进程写共享内存的时候其他进程不能读内存
首先定义了一个包含公用函数的头文件sharemem.h
#pragma once//这是C的毕竟我用的都是g编译器
#includestdio.h
#includestdlib.h
#includeunistd.h
#includesys/types.h
#includesys/ipc.h
#includesys/sem.h
#includesys/shm.h
#includeerrno.h
#define SHM_SIZE 1024
union semun{int val;struct semid_ds *buf;unsigned short *array;
};
int createsem(const char *pathname,int proj_id,int members,int init_val){//创建信号量集key_t msgkey;int index,sid;union semun semopts;if((msgkeyftok(pathname,proj_id))-1){perror(ftok error!\n);return -1;}if((sidsemget(msgkey,members,IPC_CREAT|0666))-1){//创建信号量集perror(semget call failed.\n);return -1;}semopts.valinit_val;for(index0;indexmembers;index){semctl(sid,index,SETVAL,semopts);//设置信号量的初值}return sid;
}
int opensem(const char *pathname,int proj_id){//打开信号量集key_t msgkey;int sid;if((msgkeyftok(pathname,proj_id))-1){perror(ftok error!\n);return -1;}if((sidsemget(msgkey,0,IPC_CREAT|0666))-1){perror(semget call failed.\n);return -1;}return sid;//返回信号量集的id
}
int sem_p(int semid,int index){//p操作消耗信号量struct sembuf buf{0,-1,IPC_NOWAIT};if(index0){perror(index of array cannot equals a minus value);return -1;}buf.sem_numindex;if(semop(semid,buf,1)-1){perror(a wrong operation to semaphore occurred!);return -1;}return 0;
}
int sem_v(int semid,int index){//v操作增加信号量struct sembuf buf{0,1,IPC_NOWAIT};if(index0){perror(index of array cannot equals a minus value);return -1;}buf.sem_numindex;if(semop(semid,buf,1)-1){perror(a wrong operation to semaphore occurred!);return -1;}return 0;
}
int sem_delete(int semid){//删除信号量集return semctl(semid,0,IPC_RMID);
}
int wait_sem(int semid,int index){//等待信号量while (semctl(semid,index,GETVAL)0)//如果信号量等于0也就是没有资源就等待{sleep(1);}return 1;
}
int createshm(const char *pathname,int proj_id,size_t size){//创建共享内存key_t shmkey;int sid;if((shmkeyftok(pathname,proj_id))-1){perror(ftok error!\n);return -1;}if((sidshmget(shmkey,size,IPC_CREAT|0666))-1){perror(shmget call failed.\n);return -1;}return sid;
}
writer和reader程序两程序在进入共享内存区之前都要检查信号量的值是否为1相当于是否能进入共享内存区如果不为1调用sleep()进入睡眠状态直到信号值变为1。进入共享内存区之后将信号的值减1相当于加锁这样就实现了互斥的访问共享资源。在退出共享内存区的时候将信号量加1相当于解锁。
writer
#includesharemem.h
#includestring.h
int main(){int semid,shmid;char *shmaddr;char write_str[SHM_SIZE];if((shmidcreateshm(.,m,SHM_SIZE))-1){//创建或打开共享内存exit(1);}if((shmaddr(char *)shmat(shmid,NULL,0))(char *)-1){//获取共享内存的地址perror(attach shared memory error!\n);exit(1);}if((semidcreatesem(.,s,1,1))-1){//创建信号量集exit(1);}while(1){wait_sem(semid,0);//先等信号量解锁sem_p(semid,0);//在获取资源给信号量上锁printf(writer:);fgets(write_str,1024,stdin);//从标准输入读入int lenstrlen(write_str)-1;write_str[len]\0;strcpy(shmaddr,write_str);//写入共享内存sleep(10);sem_v(semid,0);//解锁sleep(10);}
}
reader
#includesharemem.h
#includestring.h
int main(){int semid,shmid;char *shmaddr;char write_str[SHM_SIZE];if((shmidcreateshm(.,m,SHM_SIZE))-1){exit(1);}if((shmaddr(char *)shmat(shmid,NULL,0))(char *)-1){perror(attach shared memory error!\n);exit(1);}if((semidopensem(.,s))-1){//打开信号量集exit(1);}while(1){printf(reader:);wait_sem(semid,0);sem_p(semid,0);printf(%s\n,shmaddr);//读入共享内存sleep(10);sem_v(semid,0);sleep(10);}
}
编译因为是自己编写的头文件需要加-I选项这里我的头文件和cpp文件是同一路径所以用的就是.请根据自己的路径来。 最后在运行 reader会在writer发送信息10s后打印信息。 写在最后
由于本人要考研了播客可能不会再长更。这本《Linux C编程实战》其实也差不多完结了还剩网络编程章节没有讲我肯定是没时间讲了可能考研失败了会回来继续。《Primer C》的课后题还有第八章的存货后续章节只能随缘更新。Qt部分真烂尾了写Qt项目的注释实在太累了。最有可能更新的部分是力扣题讲解因为写来准备复试上机。
最后祝大家也祝我一切顺利