《linux进程间通信消息队列信号量共享内存等.pptx》由会员分享,可在线阅读,更多相关《linux进程间通信消息队列信号量共享内存等.pptx(70页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军Linux进程间通信(下)Linux IPC programme桂电嵌入式交流群:156619189Linux 培培训训课程目标lSystem V IPC 接口简介System V 消息队列消息队列System V 信号量System V 共享内存lPOSIX IPC接口Posix 消息队列Posix 信号量信号量Posix 共享内存共享内存Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军桂电嵌入式交流群:156619189Linux 培培训训System V IPC 接口l由于历史原因, linux下
2、的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的 .lUnix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同 贝尔实验室对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,通信进程局限在单个计算机内 .BSD则形成了基于套接口(socket)的进程间通信机制 ,可以在跨机器进行通信.l由于Unix版本的多样性,电子电气工程协会(IEEE)开发了一个独立的Unix标准,这个新的ANSI Unix标准被称为计算机环境的可移植性操作系统界面(POSIX)。 他也发展出
3、一套新的IPC接口.Linux 本身支持POSIX接口.因此也支持POSIX的IPC接口l最初Unix IPC包括:管道、FIFO、信号 , System V IPC包括:System V消息队列、System V信号灯、System V共享内存区 , Posix IPC包括: Posix消息队列、Posix信号灯、Posix共享内存区。l System V IPC通常在多个操作系统均实现,包括一般的嵌入式Linux系统,因此本课程主要介绍system V IPCLinux 培培训训Linux 的IPCLinux 培培训训lSystemV IPC指以下三种类型的IPC:SystemV消息队列
4、sys/msg.hSystemV信号灯 sys/sem.hSystemV共享内存区 sys/shm.hl创建或打开函数创建或打开函数msgget,semget,shmgetl控制操作函数控制操作函数msgctl,semctl,shmctll操作函数操作函数 msgsnd,msgrcv,semop,shmat,shmdtLinux 培培训训System V关键字l每一个System V 对象(消息队列,共享内存和信号量)创建时,需要的第一个参数是整数的Key值,头文件把key_t定义为一个整数lSystem V 创建对象时假设进行IPC通讯双方都取了相同的key值.这样将双方关联起来l生成key
5、的方法有三种双方直接设置为一个相同的整数为key值用IPC_PRIVA让系统自动产生一个key值,用ftok函数将一个路径转换为key值Linux 培培训训ftok函数lftok函数把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键(IPC key):#include key_t ftok(const char *pahtname, int id);l如果pathname不存在,或者对调用进程不可访问,ftok返回-1 l不能保证两个不同的路径名与同一个id值的组合产生不同的键。 l用于产生键的pahtname不能是服务器存活期间由它反复创建并删除的文件,否则会导致fto
6、k多次调用返回不同的值 Linux 培培训训System V IPC的类型l报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。 l共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。l信号量(semaphore):主要作为进程间以及同一进程不同线程之间的
7、同步手段。 Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军桂电嵌入式交流群:156619189Linux 培培训训消息队列l消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。 l消息队列能够克服早期unix通信机制的一些缺点 ,如数据量小,没有实时性Linux 培培训训消息队列(2)l消息队列消息通常要以一个long mtype放在消息开始, mtype成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型struc
8、t msgbuf long mtype; char mtext1; ; l消息队列与管道以及有名管道相比,具有更大的灵活性 它提供有格式字节流,有利于减少开发人员的工作量 消息具有类型,在实际应用中,可作为优先级使用。这两点是管道以及有名管道所不能比的 消息队列可以在几个进程间复用,而不管这几个进程是否具有亲缘关系,这一点与有名管道很相似;但消息队列是随内核持续的,与有名管道(随进程持续)相比,生命力更强,应用空间更大。 Linux 培培训训消息队列编程l头文件#include #include #include lmsgget打开或创建消息队列int msgget(key_t key, in
9、t msgflg) ;返回线队列IDlmsgrcv从队列接收消息int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg); lmsgsnd 向队列发送消息int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg); lmsgctl 发送队列控制命令msgctl(int msqid, int cmd, struct msqid_ds *buf); 共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。 Li
10、nux 培培训训消息队列数据结构l对于系统中的每个System V消息队列,内核维护一个如下的结构:struct msqid_ds struct ipc_perm msg_perm; /* operation permission struct */ struct msg *msg_first; /* ptr to first message on q */ struct msg *msg_last; /* ptr to last message on q */ unsigned short msg_cbytes; /* current # bytes on q */ msgqnum_t ms
11、g_qnum; /* # of messages on q */ msglen_t msg_qbytes; /* max # of bytes on q */ pid_t msg_lspid; /* pid of last msgsnd */ pid_t msg_lrpid; /* pid of last msgrcv */ time_t msg_stime; /* last msgsnd time */ time_t msg_rtime; /* last msgrcv time */ time_t msg_ctime; /* last change time */;Linux 培培训训msg
12、get函数 l#include lint msgget(key_t key, int oflag);返回:成功时为非负标识符,出错时为-1用于创建一个新的SystemV消息队列或访问一个已经存在的消息队列。l参数key和oflag的说明见前。lOflag :取值取值,IPC_CREAT 创建新对象成功,IPC_EXCL检查新对象l返回值是一个整数标识符,其他三个msg函数用它来指代该队列。l当创建一个消息队列时,msqid_ds结构的如下成员被初始化:msg_perm结构的uid和cuid被设置为当前进程的有效用户ID,gid和cgid被设置为当前用户的有效组ID; oflag中的读写权限位存
13、放在msg_perm.mode中; msg_qnum、msg_lspid、msg_lrpid、msg_stime和msg_rtime被置为0; msg_ctime被设置成当前时间; msg_qbytes被设置为系统限制值。 Linux 培培训训msgsnd函数 l#include lint msgsnd(int msgid, const void *ptr, size_t length, int flag);l返回:成功时为0,出错时为-1l该函数用于往消息队列上放置一个消息。lmsgid是msgget返回的标识符,ptr是一个结构指针,该结构有如下的模板:struct msgbuf long
14、 mtype; /* message type, must be 0 */ char mtext 1 ; /* message data */;l消息类型mtype必须大于0,因为非正消息类型有特殊的指示作用。llength参数以字节为单位指定待发送消息的长度。这是位于长整数消息类型之后的用户自定义数据的长度,该长度可以是0。lflag参数可以是0,也可以是IPC_NOWAIT。IPC_NOWAIT标志使得msgsnd调用非阻塞。当有如下情形之一时:在指定的队列中已经有太多的字节(对应msqid_ds结构中的msg_qbytes值); 在系统范围存在太多的消息。 若设置了IPC_NOWAIT,
15、则msgsnd立即返回,返回一个EAGAIN错误。若未指定该标志,则msgsnd阻塞,直到具备存放新消息的空间; 有msgid标识的消息队列被删除,此时返回EIDRM错误; 被信号中断,此时返回EINTR错误。Linux 培培训训msgrcv函数 l#include lssize_t msgrcv(int msqid, void *ptr, size_t length, long type, int flag);l返回:成功时为读入缓冲区中数据的字节数,出错时为-1l该函数从某个消息队列中读出一个消息。lptr参数指定所接收消息的存放位置。跟msgsnd一样,该指针指向紧挨在真正的消息数据之前
16、返回的长整数类型字段。llength指定由ptr指向的缓冲区中数据部分的大小。这是该函数能返回的最大数据量。该长度不包含长整数类型字段。ltype指定希望从所给定的队列中读出什么样的消息:type为0,返回队列中第一个消息。每个消息队列是作为一个FIFO链表维护的,所以返回的是队列中最早的消息。 type大于0,返回其类型值为type的第一个消息。 type小于0,返回其类型值小于或等于type参数的绝对值的消息中类型值最小的第一个消息。 lflag参数指定所请求的消息不在队列中时怎么办。在没有消息时,若设置了IPC_NOWAIT标志,则函数立即返回一个ENOMSG错误;否则,调用者阻塞直到如
17、下某个时间发生:l有一个所请求类型的消息可获取; l由msqid标识的消息队列被删除,此时返回个EIDRM错误; l被某个捕获的信号中断,此时返回EINTR错误。 Linux 培培训训msgctl函数 l#include lint msgctl(int msqid, int cmd, struct msqid_ds *buf);l返回:成功时为0,出错时为-1l该函数提供在一个消息队列上的各种控制操作。lmsgctl提供三个命令:IPC_RMID:从系统中删除由msqid指定的消息队列。当前在该队列上的任何消息都被丢弃。此时。第三个参数忽略不用。 IPC_SET:给指定的消息队列设置其msqi
18、d_ds结构的以下四个成员:msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_perm.qbytes。它们的值来自buff指向的结构中的相应成员。 IPC_STAT:通过buff参数给调用者返回所指定消息队列中的当前msqid_ds结构。Linux 培培训训消息队列打开l如果没有调用 msgctl(semid,IPC_RMID,0)删除消息队列,则消息队列一直存在内核中,即便是创建进程已经退出也是如此,这个用ipcs可以看到l如果对一个已经创建的消息队列的路径再次创建消息队列,通常都会出错.因此可以采用一种保险的写法/* 首先查询这个队列是否创建,如创建直
19、接用它*/if(msgid =msgget(key,IPC_EXCL|0666) = -1)/*没有创建才去创建这个消息队列*/msgid=msgget(key,IPC_CREAT|IPC_EXCL|00666);if(msgid=-1) printf(msg create errorn); return;l其它对象也用这样打开方法Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军桂电嵌入式交流群:156619189Linux 培培训训信号量l信号量与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制。 l信号量相当是一个全局的整数变量,这个变量只能用原子操
20、作来改变值l信号灯与其它进程间通信方式有所不同,它主要用于进程间同步。通常所说的系统V信号灯实际上是一个信号灯的集合,可用于多种共享资源的进程间同步。每个信号灯都有一个值,可以用来表示当前该信号灯代表的共享资源可用(available)数量,l如果一个进程要申请共享资源,那么就从信号灯值中减去要申请的数目,如果当前没有足够的可用资源,进程可以睡眠等待,也可以立即返回。当进程要申请多种共享资源时,linux可以保证操作的原子性,即要么申请到所有的共享资源,要么放弃所有资源,这样能够保证多个进程不会造成互锁。 Linux 培培训训信号量集的数据结构lSystemV信号灯是信号灯集的概念:一个或多个
21、信号灯构成一个集合。对于系统每个信号灯集,内核维护如下的一个结构:struct semid_ds struct ipc_perm sem_perm; /* operation permission struct */ struct sem *sem_base; /* ptr to first semaphore in set */ unsigned short sem_nsems; /* # of semaphores in set */ time_t sem_otime; /* last semop time */ time_t sem_ctime; /* last change time
22、*/;l当前信号灯集中的每个信号灯对应一个sem结构。定义如下:struct sem signed short semval; /* semaphore text map address */ pid_t sempid; /* pid of last operation */ unsigned short semncnt; /* # awaiting semval cval */ unsigned short semzcnt; /* # awaiting semval = 0 */;Linux 培培训训关于关于P原语原语lP原语:原语:P是荷兰语Proberen(测试)的首字母。为阻塞原语,负
23、责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;P原语的操作过程lsem减1;l若sem减1后仍大于或等于零,则进程继续执行;l若sem减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。System V 实现代码 int p(int semid) struct sembuf sops=0,+1,IPC_NOWAIT; return (semop(semid,&sops,1);Linux 培培训训关于关于V原语原语lV原语V是荷兰语Verhogen(增加)的首字母。为唤醒原语,
24、负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之V原语的操作过程lsem加1; l若相加结果大于零,则进程继续执行; l 若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。 System V 实现代码int v(int semid) struct sembuf sops=0,-1,IPC_NOWAIT; return (semop(semid,&sops,1);Linux 培培训训信号量的处理流程信号量的处理流程 l用到头文件#incl
25、ude #include #include lsemget创建或打开一个信号量int semget(key_t key, int nsems, int semflg) lSemop()对信号量 +1 或 -1 或测试是否为0 int semop(int semid, struct sembuf *sops, unsigned nsops); linux可以增加或减小信号量的值,相应于对共享资源的释放和占有 lsemctl 对信号量进行各种控制int semctl(int semid,int semnum,int cmd,union semun arg) Linux 培培训训semget函数 l
26、#include lint semget(key_t key, int nsems, int oflag);l返回:成功时为非负标识符,出错时为-1l创建一个信号灯集或访问一个已存在的信号灯集。l返回值是信号灯标识符,供其他信号灯函数使用。lnsems是集合中的信号灯数。如果不是创建一个信号灯集,而只是访问已存在的集合,则该参数可以指定为0。一旦创建完毕一个信号灯集,就不能改变其中的信号灯数。l当实际操作为创建一个新的信号灯集时,semid_ds结构的以下成员将被初始化:sem_perm结构的uid和cuid被设置为调用进程的有效用户ID,gid和cgid被设置为调用进程的有效组ID; ofl
27、ag参数中的读写权限存入sem_perm.mode中; sem_otime被设置为0,sem_ctime被置为当前时间; sem_nsems被置为nsems参数的值; 与该集合中每个信号灯关联的各个sem结构并不初始化。这些结构必须是在以SETVAL或SETALL命令调用semctl时初始化的。Linux 培培训训信号量创建问题lSystemV信号灯的创建和初始化需两次函数调用是一个致命的缺陷,这会导致竞争状态的出现。l解决竞争状态的方法是:当semget创建一个新的信号灯集时,其semid_ds结构的sem_otime成员保证被设置为0。该成员只是在semop调用成功时才被设置为当前值。在调
28、用semget进行访问而不是创建时,以IPC_STAT命令调用semctl,然后等待sem_otime变为非零值。到时就可断定该信号灯已经被初始化,而且对它初始化的进程已成功完成semop调用。所以,创建该信号灯集的进程必须初始化它的值,而且必须在任何其他进程可以使用该信号灯集之前调用semop。l这样将会造成程序相当复杂Linux 培培训训semop函数 l#include lint semop(int semid, struct sembuf *opsptr, size_t nops);l返回:成功时为0,出错时为-1l对一个或多个信号灯进行操作。lopsptr指向如下结构模板的数组(该结
29、构可能不止如下几个成员):struct sembuf shrot sem_num; /* semaphore number:0,1,.,nsems-1 */ short sem_op; /* semaphore operation: 0 */ short sem_flg; /* operation flags:0,IPC_NOWAIT,SEM_UNDO */;lnops参数指出结构数组中元素的个数。每个元素给目标信号灯集中某个信号灯指定一个操作。特定的信号灯由sem_num指定;sem_op指定特定的操作;sem_flg指定非阻塞(IPC_NOWAIT)、恢复等标志。在阻塞、非阻塞情况下返回的
30、错误情况与其他SystemV IPC相同。lsemop函数由内核保证原子的执行,内核或者完成所有操作,或者什么也不做。lsemop操作的具体描述:如果sem_op是正数,其值就加到semval(信号灯的当前值)上,这对应于释放由某个信号灯控制的资源。如果指定了SEM_UNDO标志,就从相应信号灯的semadj值中减掉sem_op的值。 如果sem_op是0,那么调用者希望等待到semval变为0,如果semval已经是0,则立即返回;如果semval不为0,相应信号灯的semzcnt(等待semval变为0的线程数)值就加1,调用线程阻塞到semval变为0(那时semzcnt再减1)。若指定
31、了IPC_NOWAIT,则调用线程不会睡眠,返回EAGAIN。 如果sem_op是负数,那么调用者希望等待semval变为大于或等于sem_op的绝对值,这对应于分配资源。如果semval大于或等于sem_op的绝对值,则从semval中减掉sem_op的绝对值,如果指定了SEM_UNDO,那么sem_op的绝对值就加到相应信号灯的semadj值上。如果semval小于sem_op的绝对值,相应信号灯的semncnt值就加1,调用线程阻塞直到semval变为大于或等于sem_op的绝对值。若指定了IPC_NOWAIT,则调用线程不会睡眠,返回EAGAIN。 lsemadj称为指定信号灯针对调用
32、进程的调整值。当调用进程终止时,semadj的值就加到相应信号灯的semval上。若调用进程对某个信号灯的全部操作都指定SEM_UNDO标志,则该进程终止时,该信号灯的值就会变得像根本没有运行过该进程一样,这就是复旧(undo)的本意。Linux 培培训训semop的调用问题lsemop采用复杂的信号灯集做参数,因此造成程序调用变得复杂.l信号灯的值加1,或值减1都在semop完成,相当于加锁或解锁都是有一个函数完成,这也是与其它互质量等其它同步机制不一样的地方l一般是将其封装成P,V原语的函数来操作/* 申请资源,用P原语*/int semaphore_wait_p(int sem_id)
33、struct sembuf sb;sb.sem_num = 0;sb.sem_op = -1;sb.sem_flg = SEM_UNDO;if (semop(sem_id, &sb, 1) = -1) fprintf(stderr, semaphore_p failedn);return (-1);return 0;/* 释放或分配资源用,用V原语 */int semaphore_signal_v(int sem_id) struct sembuf sb;sb.sem_num = 0;sb.sem_op = 1;sb.sem_flg = SEM_UNDO;if (semop(sem_id, &
34、sb, 1) = -1) fprintf(stderr, semaphore_v failedn);return (-1);return 0;Linux 培培训训semctl函数 l#include lint semctl(int semid, int semnum, int cmd, /* union arg */);l返回:成功时为非负值,出错时为-1l对一个信号灯执行各种控制操作。lsemnum标识某个信号灯,semnum仅仅用于GETVAL、SETVAL、GETNCNT、GETZCNT和GETPID命令。l第四个参数是可选的,它依赖于第三个参数cmd。它是一个联合:union semu
35、n int val; /* used for SETVAL only */ struct semid_ds *buf; /* used fro IPC_SET and IPC_STAT */ ushort *array; /* used for GETALL and SETALL */;l该联合没有出现在任何系统头文件中,由应用程序声明。而且它是以值传递的,而不是以引用传递的。Linux 培培训训semop命令选项lGETVAL:把semval的当前值作为函数返回值返回。 lSETVAL:把semval设置为arg.val。如果操作成功,那么相应信号灯在所在进程中的调整值(semadj)将被置
36、为0。 lGETPID:把sempid的当前值作为函数值返回。 lGETNCNT:把semncnt的当前值作为函数值返回。 lGETZCNT:把semzcnt的当前值作为函数值返回。 lGETALL:返回所指定信号灯集的每个成员的semval值。这些值通过arg.array指针返回。函数本身返回值为0。注意,调用者必须分配足够容纳所指定信号灯集中所有成员的semval值的一个unsigned short整数数组,然后把arg.array设置成指向这个数组。 lSETALL:设置所指定信号灯集中每个成员的semval值。这些值通过arg.array数组指定。 lIPC_RMID:把由semid指
37、定的信号灯集从系统中删除。 lIPC_SET:设置semid_ds结构中的以下三个成员:sem_perm.uid、sem_perm.gid和sem_perm.mode。这些值来自由arg.buf参数指向的结构中相应成员。semid_ds中的sem_ctime成员也被设置为当前值。 lIPC_STAT:通过arg.buf参数返回当前的semid_ds结构。注意,调用者必须首先分配一个semid_ds结构,并把arg.buf设置为指向这个结构。Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军桂电嵌入式交流群:156619189Linux 培培训训共享内存数据表示l对于每个Sy
38、stem V共享内存区,内核维护如下的信息结构:struct shmid_ds struct ipc_perm shm_perm; /* operation permission struct */ size_t shm_segsz; /* size of segment in bytes */ pid_t shm_lpid; /* pid of last shmop */ pid_t shm_cpid; /* pid of creator */ shmatt_t shm_nattch; /* current # attached */ shmat_t shm_cnattch; /* in-c
39、ore # attached */ time_t shm_atime; /* last shmat time */ time_t shm_dtime; /* last shmdt time */ time_t shm_ctime; /* last change time */;Linux 培培训训System V 共享内存使用流程l使用头文件#include #include lshmget() 获得共享内存区域的ID 如果不存在指定的共享区域就创建相应的区域。 int shmget(key_t key,int size,int shmflg); lshmat()把共享内存区域映射到调用进程的
40、地址空间中去 这样,进程就可以方便地对共享区域进行访问操作。void *shmat(int shmid,const void *shmaddr,int shmflg); lshmdt()调用用来解除进程对共享内存区域的映射 int shmdt(const void *shmaddr); lShmctl()实现对共享内存区域的控制操作 int shmctl(int shmid,int cmd,struct shmid_ds *buf); Linux 培培训训shmget函数 l#include lint shmget(key_t key, size_t size, int oflag);l返回:
41、成功时为共享内存区对象,出错时为-1l函数创建一个尚未存在的共享内存区,或者访问一个已存在的共享内存区。l返回值是共享内存区标识符,供其他函数使用。lsize参数以字节为单位指定内存的大小。当实际操作为创建一个新的内存区时,必须指定一个不为0的size值;如果实际操作是访问一个已存在的共享内存区,则size应为0。l当实际操作为创建一个新的内存区时,该内存区被初始化为size个字节的0。Linux 培培训训shmat函数 l#include lvoid * shmat(int shmid, const void *shmaddr, int flag);l返回:成功时为映射区的其始地址,出错时为
42、-1l调用shmat将共享内存区附接到调用进程的地址空间。lshmid是shmget的返回值。shmat的返回值是所指定的共享内存区在调用进程内的起始地址。确定此地址的规则如下:如果shmaddr是空指针,则系统替调用者选择地址。这是推荐(也是可移植性最好的)方法。 如果shmaddr非空,则返回地址取决于调用者是否给flag参数指定了SHM_RND值。如果SHM_RND没有指定,则共享内存区附接到由shmaddr指定的地址;若指定SHM_RND,则附接到由shmaddr指定的地址向下舍入一个SHMLBA常值。LBA代表“低端边界地址(lower boundary address)”。 lfl
43、ag参数可以指定SHM_RDONLY值,它限定只读访问。Linux 培培训训shmdt函数 l#include lint shmdt(const void *shmaddr);l返回:成功时为0,出错时为-1l调用shmdt断开与共享内存区的连接。l当一个进程终止时,它的所有当前附接着的共享内存区都自动断接掉。Linux 培培训训shmctl函数 l#include lint shmctl(int shmid, int cmd, struct shmid_ds *buff);l返回:成功时为0,出错时为-1l函数提供三个命令:IPC_RMID:从系统中删除由shmid标识的共享内存区并拆除它。
44、 IPC_SET:给所指定的共享内存区设置其shmid_ds结构的以下三个成员:shm_perm.uid、shm_perm.gid和shm_perm.mode,它们的值来自参数中的相应成员。shm_ctime的值用当前时间替换。 IPC_STAT:向调用者返回所指定共享内存区的当前shmid_ds结构。 Linux 培培训训关于System V的维护命令l可以用ipcs命令查看system V对象l用ipcrm可以删除system V 对象ipcrm sem 196632 l删除semid 为196632的信号量ipcrm shm 12395l删除shmid 为12395的共享内存ipcrm
45、msg 234l删除msgid为 234的消息队列Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军桂电嵌入式交流群:156619189Linux 培培训训两大类应用接口区别lSystem V IPC存在时间比较老,许多系统都支持,而Posix IPC是新出的标准.很多嵌入式平台只支持System V 的接口lSystem V的接口相对复杂,而POSIX比较简单,优先选择后者.参见system V的信号量和Posix信号量的操作比较lPOSIX IPC是线程安全的lSystem V内置在glibc中,因此所有使用glibc库的环境都可以使用,POSIX IPC的使用必须链接
46、librt.XXX库,(即使用-lrt参数)Linux 培培训训POSIX 消息队列接口名称接口名称目的目的mq_open(3RT) 连接到以及创建(可选)命名消息队列连接到以及创建(可选)命名消息队列mq_close(3RT) 结束到开放式消息队列的连接结束到开放式消息队列的连接mq_unlink(3RT) 结束到开放式消息队列的连接,并在最后一个进程关闭此队结束到开放式消息队列的连接,并在最后一个进程关闭此队列时将其删除列时将其删除mq_send(3RT) 将消息放入队列将消息放入队列mq_receive(3RT) 在队列中接收(删除)最早且优先级最高的消息在队列中接收(删除)最早且优先级
47、最高的消息mq_notify(3RT) 通知进程或线程消息已存在于队列中通知进程或线程消息已存在于队列中mq_setattr(3RT), mq_getattr(3RT) 设置或获取消息队列属性设置或获取消息队列属性Linux 培培训训POSIX消息队列使用l使用头文件使用头文件mqueue.hl队列数据结构队列数据结构 mqd_tl打开队列打开队列mqd_t mq_open(const char *name, int oflag, /* unsigned long mode, mq_attr attr */ .); l关闭队列关闭队列Linux 培培训训POSIX 信号量 lPosix信号量的
48、使用远比System V信号量简单.而且支持多种操作系统.lsem_open(3RT) 连接到以及创建(可选)命名信号量连接到以及创建(可选)命名信号量lsem_init(3RT) 初始化信号量结构(在调用程序内部,因此不是命名信号量)初始化信号量结构(在调用程序内部,因此不是命名信号量)lsem_close(3RT) 结束到打开信号量的连接结束到打开信号量的连接lsem_unlink(3RT) 结束到打开信号量的连接,并在最后一个进程关闭此信号量时将其删除结束到打开信号量的连接,并在最后一个进程关闭此信号量时将其删除lsem_destroy(3RT) 销毁信号量结构(在调用程序内部,因此不是
49、命名信号量)销毁信号量结构(在调用程序内部,因此不是命名信号量)lsem_getvalue(3RT) 将信号量的值复制到指定整数中将信号量的值复制到指定整数中lsem_wait(3RT)、sem_trywait(3RT) 当其他进程拥有信号量时进行阻塞,或者当其他进程拥有信号量时返回错误当其他进程拥有信号量时进行阻塞,或者当其他进程拥有信号量时返回错误lsem_post(3RT) 递增信号量计数递增信号量计数Company nameLinux培培训训主讲人:肖勇军主讲人:肖勇军桂电嵌入式交流群:156619189Linux 培培训训共享内存l共享内存可以说是最有用的进程间通信方式,也是最快的I
50、PC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。l由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。l共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据1:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。 l共享内存广泛被应用数据库系统实现到驱动程序各种应用 Linux 培培训训共享内存的实现lLinux有三种共