1 / 43

架构平台部 IPC 通讯培训 [ 共享内存 , 管道 , 信号量 ]

架构平台部 IPC 通讯培训 [ 共享内存 , 管道 , 信号量 ]. 讲师: felixzhu 日期: 2009 年 08 月 12 日. 课程简介. 通过本课程,您将了解到 Linux IPC 通讯的相关技术:共享内存,管道,信号量。重点介绍了各个 IPC 技术的优缺点和应用场景, Linux 系统提供的 IPC 相关 API ,在课程的最后给出了一些 IPC 相关的习题和参考资料。. 目录. 进程间通讯 (IPC) 线程间同步 Linux IPC: 共享内存 (Shared Memory) Linux IPC: 管道 (Pipe)

jed
Download Presentation

架构平台部 IPC 通讯培训 [ 共享内存 , 管道 , 信号量 ]

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 架构平台部IPC通讯培训[共享内存,管道,信号量]架构平台部IPC通讯培训[共享内存,管道,信号量] 讲师:felixzhu 日期:2009年08月12日

  2. 课程简介 • 通过本课程,您将了解到Linux IPC通讯的相关技术:共享内存,管道,信号量。重点介绍了各个IPC技术的优缺点和应用场景,Linux系统提供的IPC相关API,在课程的最后给出了一些IPC相关的习题和参考资料。

  3. 目录 • 进程间通讯(IPC) • 线程间同步 • Linux IPC: 共享内存(Shared Memory) • Linux IPC: 管道(Pipe) • Linux IPC: 信号量(Semaphore) • Linux IPC 实践(Ready & Rock) • 参考资料(Reference)

  4. 自我简介 felixzhu (朱建平) 1999 ~ 2006 WuHan University Intrested Area: Win32 开发(GUI,COM/AtiveX,Network) P2P Streaming, P2P VOD, Distributed System Win32 Reverse Enginering Linux Server Programming RIA :Flash ActionScript …

  5. 进程间通讯(IPC) 共享内存 信号量(集) 消息队列 管道(匿名& 命名) 信号量 Socket( Unix domain socket) 文件(Shell中用得比较多)

  6. 线程间同步 • Linux pthread库提供的三种线程同步机制: 互斥锁 : pthread_mutex_t 条件变量: pthread_cond_t 读写锁 : pthread_rwlock_t • Win32 事件 :Event 临界区 : CRITICAL_SECTION

  7. POSIX • POSIX : Portable Operating System Interface of Unix • POSIX包含了众多的扩展: POSIX:SEM匿名信号量和命名信号量 POSIX:XSI共享内存,信号量集和消息队列,间隔定时器... POSIX:TMR定时器 … POSIX扩展不仅定义了API接口,还规范了相关的工具和命令,如POSIX:XSI中就提供了列举和删除相关实体的命令解释程序命令 ipcs和 ipcrm

  8. 共享内存 • 共享内存 • 共享内存是内核为进程创建的一个特殊内存段,它可连接(attach)到自己的地址空间,也可以连接到其它进程的地址空间 • 最快的进程间通信方式 • 不提供任何同步功能

  9. 共享内存原理图

  10. 共享内存的应用场景 • 进程退出后,共享内存仍然保留,下次进程启动后Attach到共享内存继续使用 比如:基于共享内存的Cache系统, TFS的内存Cache实现:CacheAccess

  11. 共享内存的应用场景 • 进程间通讯,一般和信号量结合使用 比如:TFS的队列: tfc::net::CFifoSyncMQ

  12. 共享内存:POSIX vs System V Posix共享内存与System V共享内存区别: • Posix共享内存区对象的大小可在任何时刻通过调用ftruncate 修改,而System V共享内存区对象的大小是在调用shmget创建时固定下来。 System V共享内存后来被POSIX采纳,即现在的POSIX:XSI共享内 存

  13. POSIX共享内存API #include <sys/types.h> #include <sys/mman.h> #include <fcntl.h> int shm_open(const char *name, int oflag, mode_t mode); int shm_unlink(const char *name); #include <sys/mman.h> void* mmap (void* addr, size_t len, int prot, int flags, int fildes, off_t off); #include <unistd.h> int ftruncate (int fildes, off_t length);

  14. System V共享内存 POSIX:XSI API #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); void* shmat(int shmid, const void* shmaddr, int shmflg); int shmdt(const void* shmaddr); int shmctl(int shmid, int cmd, struct shmid_ds* buf);

  15. 共享内存使用经验 • 单进程一般配置使用小于 1.5GB的共享内存(为什么?) • 共享内存一般需要和其它IPC配合使用 基于共享内存的HashMap 基于共享内存的FIFO队列 … • 共享内存在进程退出后不会丢失,仅在重启后共享内存的数据会丢失(Dump + Binlog机制可用于备份共享内存中的数据)

  16. POSIX:XSI 工具 ipcs 命令: 显示与POSIX:XSI进程间通讯资源有关的信息. ipcs [-qms] [-a | -bcopt] ipcrm命令: 删除POSIX:XSI 进程间通讯的资源. ipcrm [-q msgid | -Q msgkey | -s semid | -S semkey | -m shmid| -M shmkey]

  17. POSIX:XSI 工具 felixzhu@172.25.38.174:~$ ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00005feb 0 root 666 12000 4 0x4000910a 18350083 felixzhu 600 33554432 0 ------ Semaphore Arrays -------- key semid owner perms nsems 0x00008708 0 root 666 1 0x4000910b 4292618 felixzhu 600 2 0x40009102 4325387 felixzhu 600 2 ------ Message Queues -------- key msqid owner perms used-bytes messages

  18. 管道:Pipe 两种类型的管道: 匿名管道: 在创建进程及其fork的后代进程中使用 命名管道: FIFO,像普通文件一样,有名字和访问权限,而且 会出现在ls列出的目录列表中。 任何具有恰当权限的进程都可以访问FIFO.

  19. 管道:匿名管道(Pipe) #include <unistd.h> int pipe(int fildes[2]); 单工模式的管道: fildes[0] 用于从管道中读取数据 fildes[1] 用于将数据写入管道

  20. 管道:匿名管道(Pipe) • if(pipe(fdes)<0) • return -1; • if((pid=fork())==0) { // 子进程 • close(fdes[1]); // 关闭写端 • r_num=read(fdes[0],r_buf,sizeof(r_buf)-1); // 向读端读取数据 • printf( "read num is %d the data read from the pipe is d\n",r_num,atoi(r_buf)); • close(fdes[0]); • exit(); • } • else if(pid>0) { // 父进程 • close(fdes[0]);//关闭读端 • strcpy(w_buf,"111"); • if(write(fdes[1],w_buf,4)!=-1) //向写端写数据 • printf("parent write over\n"); • close(fdes[1]);//write • }

  21. 管道:匿名管道(Pipe) 当进程调用了pipe

  22. 管道:匿名管道(Pipe) fork被调用后

  23. 管道:匿名管道(Pipe) 两个进程分别关闭一个端

  24. 管道:匿名管道(Pipe) 管道的读写 1、 写管道时,常数PIPE_BUF规定了内核中管道缓存器的大小 /usr/include/linux/limits.h:#define PIPE_BUF 4096 • 2、 管道破裂: 管道的一端关闭时, • a) 写端关闭,读该管道在所有数据都被读取后, • read返回0, 表示达到了文件结束 • b) 读端关闭,写该管道产生信号SIGPIPE

  25. 管道(pipe) 管道用于标准输入和标准输出 • 管道:shell中的形式 • cmd1 | cmd2 • 重定向 cmd > file • 实现代码 • 执行cmd1前 if (fd[1] != STDOUT_FILENO) { if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) err_sys(“dup2 error to stdout); } • 执行cmd2前 if (fd[0] != STDIN_FILENO) { if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) err_sys(“dup2 error to stdin); }

  26. 管道(pipe)

  27. 管道(pipe) popen, pclose: process I/O #include <stdio.h> FILE *popen(const char *command, const char *type); int pclose(FILE *stream);

  28. 管道:命名管道(FIFO) #include <sys/stat.h> int mkfifo (const char* path, mode_t mode); int unlink(const char* path) ; Shell命令操作: mkfifo命令 rm 命令

  29. 管道:命名管道(FIFO) FIFO的同步和读写 • 打开FIFO时的同步 • 一般情况下(没有说明O_NONBLOCK),只读打开要阻塞到某个其它进程为写打开此FIFO;类似的,为写打开一个FIFO要阻塞到某个其它进程为读而打开它。 • 如果指定了O_NONBLOCK,则只读打开立即返回;只写打开也立即返回,但如果没有进程已经为读而打开此FIFO,那么open将出错返回 -1,errno置为ENXIO。 • 读写FIFO时的同步 • same as pipe

  30. 管道:命名管道(FIFO) • C/S应用程序 • 例:client.c, server.c

  31. 信号量的原理

  32. 信号量 • POSIX:SEM 信号量 #include <semaphore.h> 匿名信号量 命名信号量 • POSIX:XSI 信号量集 #include <sys/sem.h> ipcs & ipcrm 工具

  33. POSIX:SEM 匿名信号量 一般用于 父子进程 之间的同步 #include <semaphore.h> int sem_init(sem_t* sem, int pshared, unsigned value); int sem_destroy(sem_t* sem); int sem_post(sem_t* sem); int sem_trywait(sem_t* sem); int sem_wait(sem_t* sem); int sem_getvalue(sem_t* restrict sem, int* restrict sval);

  34. POSIX:SEM 命名信号量 可用于任意进程间的同步 #include <semaphore.h> sem_t* sem_open(const char* name, int oflag,…); int sem_close(sem_t* sem); int sem_unlink(const char* name); int sem_post(sem_t* sem); int sem_trywait(sem_t* sem); int sem_wait(sem_t* sem); int sem_getvalue(sem_t* restrict sem, int* restrict sval);

  35. 信号量集 POSIX:XSI API #include <sys/sem.h> int semget (key_t key, int nsems, int semflg); int semctl (int semid, int semnum,int cmd, …); int semop (int semid, struct sembuf* sops, size_t nsops); int semtimedop(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout);

  36. 信号量的使用 • 使用System V的信号量集 可以方便多个信号量的管理,一个信号量集对应一个sem_key • semop 和 semtimedop 操作可能被信号中断,errno == EINTR, 在使用时注意判断下函数返回值并对EINTR的情况进行重试

  37. 课后作业: • 要求: 1. 课后作业可个人独立完成 也可 小组协作完成 (小组完成的请注明参与的小组成员) 2. 请注意 编程风格,清晰的实现思路 和 干净整洁的代码 均 会获得适当加分

  38. 课后作业1:基于共享内存的管道 • 请用C++封装一个类,该类在能够实现基于共享内存的管道功能 • 要求: 1. 当指定的共享内存不存在时,自动创建指定key 和大小的共享内存 当指定的共享内存存在时,能自动绑定并使用该共享内存 2. 接口

  39. 课后作业2:管道 • 编写一个程序(程序名:myls)包装下 ls 的功能,要求对ls的功能做一点 小调整: 当输入 ls –la 时将 total 统计行放到最好一行

  40. 课后作业3:程序设计类 编写一个 斗地主的 出牌仲裁器: • 规则参考 附件给定的规则 • 出牌仲裁器必须实现如下场景的功能: 玩家A出牌,当前轮到玩家B出牌,玩家B出牌后出牌仲裁器能够判断玩家B出的牌是否有效。 • C++语言实现

  41. 推荐书目: • 1. Linux 环境高级编程(第二版) APUE(Second Edition) • 2. Unix系统编程 (Unix Systems Programming) • 3.郑彦兴的“Linux IPC 通信机制”文章 http://blog.chinaunix.net/u2/86340/showart_1673177.html • 4.Google –Linux IPC

  42. Q&A

  43. 谢谢!

More Related