西安邮电大学Linux高级编程进程间通信资料课件

上传人:痛*** 文档编号:241778237 上传时间:2024-07-23 格式:PPT 页数:72 大小:1.31MB
返回 下载 相关 举报
西安邮电大学Linux高级编程进程间通信资料课件_第1页
第1页 / 共72页
西安邮电大学Linux高级编程进程间通信资料课件_第2页
第2页 / 共72页
西安邮电大学Linux高级编程进程间通信资料课件_第3页
第3页 / 共72页
点击查看更多>>
资源描述
第5章System V进程间通信 1 12 2System VIPC基础基础 消息队列消息队列 3 3信号量通信机制信号量通信机制 4 4共享内存共享内存 为了提供与其他系统的兼容性,Linux也支持三种System V的进程间通信机制:消息队列、信号量和共享内存消息队列、信号量和共享内存,Linux对这些机制的实施大同小异。我们把信号量、消息队列和共享内存统称System V IPC对象。就像每个文件都有一个打开文件号一样,每个对象也都有唯一的识别号,进程可以通过系统调用传递的识别号来存取这些对象。与文件的存取一样,对这些对象的存取也要验证存取权限,System V IPC可以通过系统调用对对象的创建者设置这些对象的存取权限。2024/7/232 ipcs 命令Ipcs命令用于显示消息队列、共享内存、信号量的信息。q 显示消息队列 s 显示信号量m 显示共享内存 a 详细信息对每一个资源,这个命令会显示:TYPE 包括信息队列(q),共享内存(m),或者信号量(s)。ID 资源条目的唯一的表示号KEY应用程序存取资源使用的参数。MODE 存取模式和许可权限的标记OWNER and GROUP 登录名和用户属主的组号2024/7/233key值和ID值 Linux系统为每个IPC机制都分配了唯一的ID,所有针对该IPC机制的操作都使用对应的ID。因此,通信的双方都需要通过某个办法来获取ID值。显然,创建者根据创建函数的返回值可获取该值,但另一个进程如何实现呢?由于Linux两个进程不能随意访问对方的空间(一个特殊是,子进程可以继承父亲进程的数据,实现父亲进程向子进程的单向传递),也就不能够直接获取这一ID值。为解决这一问题,IPC在实现时约定使用key值做为参数创建,如果在创建时使用相同的key值将得到同一个IPC对象的ID(即一方创建,另一方获取的是ID),这样就保证了双方可以获取用于传递数据的IPC机制ID值。2024/7/234 ftok extern key_t ftok(_const char*_pathname,int _proj_id);此函数有两个参数,pathname为文件路径名,可以是特殊文件(例如目录文件),也可以是当前目录“.”,而通常也是设置此参数为当前目录,因为当前目录一般都是存在的,且不会被立即删除。第二个参数为一个int型变量。2024/7/235例:ftok的使用#include#include main()key_t key;key=ftok(.,1);printf(the key is%xn,key);2024/7/23人民邮电出版社出版杨宗德编著6 ftok ftok函数创建key值过程中使用了该文件属性的st_dev和st_ino。具体构成如下:key值的第31-24为ftok()第二个参数的低8位;key值的第23-16为该文件的st_dev属性的低8位;key值的第15-0为该文件的st_ino属性的低16位;因此,如果使用相同的文件路径及整数,得到的key值是唯一的,而唯一的key值创建某类IPC机制时将得到同一个IPC机制(但如果使用相同的key值分别创建一个消息队列和一个信号量,两者没有联系),而文件路径的访问对两个进程来说很容易统一,因此,便捷的实现了两进程通信机制的确定。2024/7/237例:ftok函数和参数的关系#include#include#include#include main(int argc,char*argv)key_t key;int i;struct stat buf;if(argc!=3)printf(error usagen);return 1;i=atoi(argv2);2024/7/238例:ftok函数和参数的关系if(stat(argv1,&buf)=-1)perror(stat);exit(EXIT_FAILURE);printf(file st_dev=%xn,buf.st_dev);printf(file st_ino=%xn,buf.st_ino);printf(number=%xn,i);key=ftok(argv1,i);printf(key=0 x%x,key);2024/7/239第5章System V进程间通信 1 12 2System VIPC基础基础 消息队列消息队列 3 3信号量通信机制信号量通信机制 4 4共享内存共享内存 消息队列的基本概念消息队列就是一个消息的链表,是一系列保存在内核中的消息的列表。用户进程可以向消息队列添加消息,也可以从消息队列读取消息。消息队列与管道通信相比,其优势是对每一个消息指定特定消息类型,接收的时候不需要按队列次序,而是可以根据自定义条件接收特定类型的消息。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。2024/7/2311消息队列属性2024/7/2312消息struct msg结构体/come from/usr/src/kernels/uname r/inlcude/linux/msg.h/*one msg_msg structure for each message*/struct msg_msgstruct list_head m_list;long m_type;int m_ts;/*message test size */struct msg_msgseg*next;void*security;/*the actual message follows immediately*/;2024/7/2313消息队列2024/7/2314对消息队列的说明对消息队列的限定:/come from/usr/include/linux/msg.h#define MSGMNI 16 /*=IPCMNI*/*max#of msg queue identifiers*/#define MSGMAX 8192 /*=INT_MAX*/*max size of message(bytes)*/#define MSGMNB 16384 /*=INT_MAX*/*default max size of a message queue */不同的系统限制值可以通过msgctl函数使用IPC_INFO参数获得。2024/7/2315消息队列常用的系统调用函数函数功能功能ftok根据文件路径和参数生成标准keymsgget创建或打开消息队列msgsnd添加消息msgrcv读取消息msgctl控制消息队列2024/7/2316创建消息队列 extern int msgget(key_t _key,int _msgflg);第一个参数key为由ftok创建的key值。第二个参数_msgflg的低位用来确定消息队列的访问权限。如0770,为文件的访问权限类型。此外,还可以附加以下参数值。这些值可以与基本权限以或的方式一起使用。/come from/usr/include/bit/ipc.h/*resource get request flags*/#define IPC_CREAT 00001000 /*create if key is nonexistent*/#define IPC_EXCL 00002000/*fail if key exists*/#define IPC_NOWAIT 00004000/return error on wait*/2024/7/2317msgget返回说明:成功执行时,返回消息队列标识值。失败返回-1,errno被设为以下的某个值,有时也会返回0,这个时候也是可以正常使用的。EACCES:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权限EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志ENOENT:key指定的消息队列不存在,同时msgflg中不指定IPC_CREAT标志ENOMEM:需要建立消息队列,但内存不足ENOSPC:需要建立消息队列,但已达到系统的最大消息队列容量2024/7/2318例:创建消息队列#include#include#include int main()key_t key;key=ftok(.,1);printf(the key is%xn,key);int id;id=msgget(key+1,IPC_CREAT|0666);printf(id=%dn,id);system(“ipcs”);2024/7/23人民邮电出版社出版杨宗德编著19消息队列属性控制 extern int msgctl(int _msqid,int _cmd,struct msqid_ds*_ buf);第一个参数_msqid为消息队列标识符,该值为使用msgget函数创建消息队列的返回值。第二个参数_cmd为执行的控制命令,即要执行的操作。包括以下选项:/come from/usr/include/linux/ipc.h/*Control commands used with semctl,msgctl and shmctl see also specific commands in sem.h,msg.h and shm.h*/#define IPC_RMID 0 /*remove resource*/#define IPC_SET 1 /*set ipc_perm options*/#define IPC_STAT 2 /*get ipc_perm options*/#define IPC_INFO 3 /*see ipcs*/2024/7/2320例:删除消息队列#include#include#include int main()key_t key;int id;key=ftok(.,1);id=msgget(key+1,IPC_CREAT|0666);printf(id=%dn,id);msgctl(id,IPC_RMID,NULL);sytem(“ipcs”);2024/7/23人民邮电出版社出版杨宗德编著21发送信息到消息队列 extern int msgsnd(int _msqid,_const void*_msgp,size_t _msgsz,int _msgflg)第一个参数msqid为指定的消息队列标识符(由msgget生成的消息队列标识符),即将消息添加到那个消息队列中。第二个参数msgp为指向的用户定义缓冲区。第三个参数为接收信息的大小,其数据类型为size_t,即unsigned int类型。其大小为0到系统对消息队列的限定值。第四个参数用来指定在达到系统为消息队列锁定的界限(如达到字数限制)时应采取的操作。2024/7/2322发送信息到消息队列(2)第二个参数其定义如下:/come from/usr/include/linux/msg.h/*message buffer for msgsnd and msgrev calls*/struct msgbuflong mtype;/*type of message */char mtext1;/*message text*/mtype是一个正整数,由产生消息的进程生成,用于表示消息的类型,因此,接收进程可以用来进行消息选择(消息队列在存储信息时是按发送的先后顺序放置的)。mtext是文本内容,即消息内容,此处大小为1,显然不够用,在使用时自己重新定义此结构。2024/7/2323发送信息到消息队列(3)第四个参数用来指定在达到系统为消息队列锁定的界限(如达到字数限制)时应采取的操作。:如果设置为IPC_NOWAIT,如果需要等待,则不发送消息并且调用进程立即返回错误信息EAGAIN.如果设置为0,则忽略标志位。成功调用后,此函数将返回0,否则返回-1,同时将对消息队列msqid数据结构的成员执行下列操作:msg_qnum以1为增量递增。msg_lspid设置为调用进程的进程ID。msg_stime设置为当前时间。2024/7/2324从消息队列接收信息extern int msgrev(int _msqid,void*_msgp,size_t _msgsz,long int _msgtyp,int _msgflg);此函数从与msqid指定的消息队列标识符相关联的队列中读取消息,并将其放置到msgp指向的结构中。第一个参数为读的对象,即从哪个消息队列获得消息。第二个参数为一个临时消息数据结构,用来保存读取的信息。其定义与发送信息的第二个参数相同。第三个参数msgsz指定mtext的大小(以字节为单位)。如果收到的消息大于msgsz,并且msgflg&MSG_NOERROR为真,则将该消息截至msgsz字节,消息的截断部分将丢失,并且不向调用进程提供截断的提示2024/7/2325从消息队列接收信息(2)第四个参数msgtyp指定请求的消息类型:msgtyp=0 收到队列中的第一条消息,任意类型。msgtyp0 收到第一条msgtyp类型的消息。msgtyp0收到第一条最低类型(小于或等于msgtyp的绝对值)的消息。第五个参数msgflg指定所需类型消息不在队列上时将要采取的操作。0,表示忽略;IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数的进程。2024/7/2326消息队列应用实例#include#include#include#include#include#include#include struct msgmbuflong msg_type;char msg_text512;2024/7/2327消息队列应用实例 int main()int qid;key_t key;int len;struct msgmbuf msg;if(key=ftok(.,a)=-1)perror(ftok);exit(EXIT_FAILURE);if(qid=msgget(key,IPC_CREAT|0666)=-1)perror(msgget);exit(EXIT_FAILURE);2024/7/2328消息队列应用实例 printf(ID of the queue is:%dn,qid);puts(please input the mssage:);if(fgets(&msg)-msg_text,512,stdin)=NULL)puts(no message!);exit(EXIT_FAILURE);msg.msg_type=getpid();len=strlen(msg.msg_text);if(msgsnd(qid,&msg,len,0)0)perror(msgsnd);exit(EXIT_FAILURE);2024/7/2329消息队列应用实例 if(msgrcv(qid,&msg,512,0,0)msg_text);if(msgctl(qid,IPC_RMID,NULL)0)perror(msgctl);exit(EXIT_FAILURE);exit(0);2024/7/2330第5章System V进程间通信 1 12 2System VIPC基础基础 消息队列消息队列 3 3信号量通信机制信号量通信机制 4 4共享内存共享内存 信号量基本概念信号量是操作系统中解决进程或线程同步与互斥的最重要机制之一。Linux内核提供System V的信号量机制,用于实现进程之间通信。信号量常用系统调用见下表函数函数功能功能sem_init初始化一个信号量sem_wait阻塞线程sem_post增加信号量的值sem_destory释放信号量2024/7/2332信号量集合属性2024/7/2333信号量结构/come from/usr/src/kernels/uname-r/include/linux/sem.h/*One semaphore structure for each semaphore in the system.*/struct semint semval;/*current value*/int sempid;/*pid of last operation*/;2024/7/2334信号量通信机制概念图 2024/7/2335创建信号量集合 extern int semget(key_t _key,int _nsems,int _semflg);第一个参数为key_t类型的key值,一般由ftok函数产生。第二个参数_nsems为创建的信号量个数,各信号量以数组的方式存储。这个数组用于初始化数组对象。第三个参数_semflg用来标识信号量集合的权限。如0770,为文件的访问权限类型。此外,还可以附加以下参数值。这些值可以与基本权限以或的方式一起使用。/come from/usr/include/bit/ipc.h/*resource get request flags*/#define IPC_CREAT 00001000 /*create if key is non existent*/#define IPC_EXCL 00002000 /*fail if key exists */#define IPC_NOWAIT 00004000 /*return error on wait */2024/7/2336控制信号量集合、信号量extern int semctl(int _semid,int _semnum,int _cmd,)该函数最多可有四个参数(有可能只有三个参数)。第一个参数_semid为要操作的信号量集合标识符,该值一般由semget函数返回。第二个参数为集合中信号量的编号。如果标识某个信号量,此值为该信号量的下标(从0到n-1);如果标识整个信号量集合,则设置为0。第三个参数为要执行的操作,如果是对整个信号量集合,这些操作在/usr/include/linux/ipc.h文件中定义。其操作包括IPC_RMID、IPC_SET、IPC_STAT和IPC_INFO,具体含义同msgctl的相关操作。2024/7/23372024/7/2338第5章System V进程间通信 1 12 2System VIPC基础基础 消息队列消息队列 3 3信号量通信机制信号量通信机制 4 4共享内存共享内存 共享内存的基本概念共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,数据不需要在进程间复制,所以这是最快的一种IPC。使用共享内存时,多个进程之间对一给定的存储区需进行同步访问。即若一个进程正在将数据放入共享存储区,则在它做完这一操作之前,其他进程不应当去读取这些数据。通常,信号量被用来实现对共享存储的访问。2024/7/2343共享内存属性2024/7/2344共享内存与管道对比 2024/7/2346共享内存的常用函数函数函数功能功能mmap建立共享内存映射munmap解除共享内存映射shmget获取共享内存区域的IDshmctl共享内存控制shmat映射共享内存对象shmdt分离共享内存对象2024/7/2347内存映射函数mmap将某个文件的指定内容映射到内存空间中,该函数声明如下:#include void*mmap(void*start,size_t length,int prot,int flags,int fd,off_t offset);此函数将在进程的虚拟地址空间(起始为start,长度为length字节)和与文件描述符fd关联的文件(偏移量为offset,长度为length)之间建立映射。参数start一般情况下设置为NULL,由系统分配。第三个参数prot描述映射的内存权限,该参数是以下选项的组合:PORT_READ 允许读该内存 PORT_WRITE 允许写该内存PORT_EXEC 允许执行该内存段 PORT_NONE 该内存段不能被访问2024/7/2348内存映射参数flags控制程序对该内存段的改变所造成的影响,常用选项如下:MAP_PRIVATE:内存段是私有的,对他的修改只在此局部范围内有效,其他进程不可见。MAP_SHARED:共享映射,某进程对该段内存空间的更新对其他进程来说是可见的,但该文件的内容并不会立即更新,要更新文件内容,需要调用msync和munmap函数。2024/7/2349例:内存映射的使用#include#include#include#include#include typedef structchar name4;int age;people;main(int argc,char*argv)pid_t result;int i;people*p_map;char temp;2024/7/2350例:内存映射的使用p_map=(people*)mmap(NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);result=fork();if(result0)perror(fork);exit(EXIT_FAILURE);else if(result=0)sleep(2);for(i=0;i5;i+)printf(read by child:No.%ds age is:%dn,i+1,(*(p_map+i).age);2024/7/2351例:内存映射的使用(*p_map).age=110;munmap(p_map,sizeof(people)*10);exit(0);elsetemp=a;for(i=0;iname,&temp,2);(p_map+i)-age=20+i);2024/7/2352例:内存映射的使用sleep(5);printf(read by parent:the sum of age is:%dn,(*p_map).age);printf(unmapingn);munmap(p_map,sizeof(people)*10);printf(unmap successful!n);2024/7/2353创建共享内存 extern int shmget(key_t _key,size_t _size,int _shmflg);第一个参数为key_t类型的key值,一般由ftok函数产生。第二个参数size为欲创建的共享内存段大小(单位为字节)。第三个参数shmflg用来标识共享内存段的创建标识。包括/come from/usr/include/linu/ipc.h#define IPC_CREAT 01000 /*Create key if key does not exist.*/#define IPC_EXCL 020000 /*Fail if key exists.*/#define IPC_NOWAIT 04000 /*Return error on wait.*/2024/7/2354创建共享内存 另外,在/usr/include/linux/shm.h文件还定义了另外两个选项:/come from/usr/include/linux/shm.h/*permission flag for shmget */#define SHM_R 0400 /*or S_IRUGO from */#define SHM_W 0200 /*or S_IWUGO from */2024/7/2355共享内存控制 extern int shmctl(int _shmid,int _cmd,struct shmid_ds*_buf);第一个参数为要操作的共享内存标识符,该值一般由shmget函数返回。第二个参数为要执行的操作,这些操作在/usr/include/linux/ipc.h文件中定义。其操作包括IPC_RMID、IPC_SET、IPC_STAT和IPC_INFO,具体含义同msgctl的相关操作。如果是超级用户,还可以执行以下两个命令:/come from/usr/include/sys/shm.h/*super user shmctl commands */#define SHM_LOCK 11#define SHM_UNLOCK 12第三个参数为struct shmid_ds结构的临时共享内存变量信息,此内容根据第二个参数的不一样而改变。2024/7/2356映射共享内存对象进程使用共享内存前,需要将该共享内存与当前进程建立联系,即将该共享内存使用shmat函数映射到当前进程。其函数声明如下:#include extern void*shmat(int _shmid,_const void*_shmaddr,int _shmflag);如果执行成功,将返回共享内存段首地址。第一个参数_shmid为要操作的共享内存标识符,该值一般由shmget函数返回。第二个参数shmaddr指定共享内存的映射地址。如果该值为非零,则将用此值作为映射共享内存的地址,如果此值为0,则由系统来选择映射的地址。一般都将此值设置为0。2024/7/2357映射共享内存对象#include extern void*shmat(int _shmid,_const void*_shmaddr,int _shmflag);第三个参数用来指定共享内存短的访问权限和映射条件。/come from/usr/include/linux/shm.h/*mode for attach*/#define SHM_RDNOLY 010000 /*read-only access*/#define SHM_RND 020000 /*round attach attach address to SHMLBA bounary*/#define SHM_REMAP 040000 /*take-over region on attach */#define SHM_EXEC 0100000 /*execution access */2024/7/2358分离共享内存对象在共享内存使用完毕后,需要使用shmdt函数将其与当前进程分离。其函数声明如下:/come from/usr/include/sys/shm.hextern int shmdt(_const void*_shmaddr);其参数即为与当前进程分离的共享内存标志ID。2024/7/2359例一#include#include#include#include#include#include typedef structchar name4;int age;people;main()int shm_id,i;key_t key;people*p_map;char*name=/dev/shm/myshm2;2024/7/2360例一key=ftok(name,0);shm_id=shmget(key,4096,IPC_CREAT);if(shm_id=-1)perror(shmget);exit(EXIT_FAILURE);p_map=(people*)shmat(shm_id,NULL,0);for(i=0;iname);printf(age:%dn,(p_map+i)-age);if(shmdt(p_map)=-1)perror(shmdt);2024/7/2361例一#include#include#include#include#include#include typedef structchar name4;int age;people;main()int shm_id,i;key_t key;people*p_map;char*name=/dev/shm/myshm2;2024/7/2362例一key=ftok(name,0);if(key=-1)perror(ftok);exit(EXIT_FAILURE);shm_id=shmget(key,4096,IPC_CREAT|0666);if(shm_id=-1)perror(shmget);exit(EXIT_FAILURE);p_map=shmat(shm_id,0,0);/(people*)shmat(shm_id,0,0);temp=a;for(i=0;iname,&temp,1);(p_map+i)-age=20+i;if(shmdt(p_map)=-1)perror(shmdt);2024/7/23人民邮电出版社出版杨宗德编著63例二#include#include#include#include#include#include#include typedef structchar str150;char str250;int no1,no2;str;2024/7/2364例二main(int argc,char*agv)int shm_id,i;key_t key;str*p_map;time_t timep;struct tm*p;char*name=/dev/shm/myshm2;key=ftok(name,0);shm_id=shmget(key,4096,IPC_CREAT|0666);if(shm_id=-1)perror(shmget);exit(EXIT_FAILURE);p_map=(str*)shmat(shm_id,NULL,0);p_map-no1=0;p_map-no2=0;printf(This is A.n);fgets(p_map-str2,sizeof(p_map-str2),stdin);p_map-no1=1;2024/7/2365例二while(1)if(p_map-no2=1)time(&timep);gmtime(&timep);p=localtime(&timep);printf(A:%s%d:%d:%dn,p_map-str1,p-tm_hour,p-tm_min,p-tm_sec);p_map-str10=0;p_map-no2=0;elsecontinue;if(p_map-no1=0)fgets(p_map-str2,sizeof(p_map-str2),stdin);p_map-no1=1;if(shmdt(p_map)=-1)perror(shmdt);2024/7/2366例二#include#include#include#include#include#include#include typedef structchar str150;char str250;int no1,no2;str;2024/7/23人民邮电出版社出版杨宗德编著67例二main(int argc,char*agv)int shm_id,i;key_t key;str*p_map;time_t timep;struct tm*p;char*name=/dev/shm/myshm2;key=ftok(name,0);shm_id=shmget(key,4096,IPC_CREAT|0666);if(shm_id=-1)perror(shmget);exit(EXIT_FAILURE);p_map=(str*)shmat(shm_id,NULL,0);p_map-no1=0;p_map-no2=0;printf(This is B.n);2024/7/23人民邮电出版社出版杨宗德编著68例二while(1)if(p_map-no1=1)time(&timep);gmtime(&timep);p=localtime(&timep);printf(A:%s%d:%d:%dn,p_map-str2,p-tm_hour,p-tm_min,p-tm_sec);p_map-no1=0;p_map-str20=0;elsecontinue;if(p_map-no2=0)fgets(p_map-str1,sizeof(p_map-str1),stdin);p_map-no2=1;if(shmdt(p_map)=-1)perror(shmdt);2024/7/23人民邮电出版社出版杨宗德编著69注意:在创建子进程时,需要注意一下几点:使用fork函数创建一个子进程后,该进程继承父进程挂载的共享内存;如果调用exec执行一个新的程序,则所有挂载的共享内存将被自动卸载;如果在某个进程中调用了exit函数,所有挂载的共享内存将与当前进程脱离关系。2024/7/23人民邮电出版社出版杨宗德编著70共享内存应用示例 共享内存的权限管理示例共享内存处理应用示例 代码见教材。2024/7/2371上机1.实现两个进程间使用消息队列进行通信。2.创建一个信号量。3.调试课件P64-69的例子。2024/7/2372
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!