43
架架架架架 IPC 架架架架 [ 架架架架 , 架架 , 架架架 ] 架架felixzhu 架架2009 架 08 架 12 架

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

  • Upload
    jed

  • View
    261

  • Download
    0

Embed Size (px)

DESCRIPTION

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

Citation preview

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

架构平台部IPC 通讯培训

[ 共享内存 , 管道 , 信号量 ]

讲师: felixzhu日期: 2009 年 08 月 12 日

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

课程简介

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

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

目录

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

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

自我简介

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

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

进程间通讯 (IPC)

共享内存 信号量(集) 消息队列管道(匿名 & 命名)信号量Socket( Unix domain socket)

文件( Shell 中用得比较多)

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

线程间同步

Linux

pthread 库提供的三种线程同步机制: 互斥锁 : pthread_mutex_t

条件变量 : pthread_cond_t

读写锁 : pthread_rwlock_t

Win32

事件 : Event

临界区 : CRITICAL_SECTION

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

POSIX

POSIX : Portable Operating System Interface of Unix

POSIX 包含了众多的扩展: POSIX:SEM 匿名信号量和命名信号量 POSIX:XSI 共享内存,信号量集和消息队列 , 间隔定时器 ... POSIX:TMR 定时器 …

POSIX 扩展不仅定义了 API 接口,还规范了相关的工具和命令,如 POSIX:XSI 中就提供了列举和删除相关实体的命令解释程序命令

ipcs 和 ipcrm

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

共享内存

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

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

共享内存原理图

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

共享内存的应用场景

进程退出后,共享内存仍然保留,下次进程启动后 Attach 到共享内存继续使用比如:基于共享内存的 Cache 系统,

TFS 的内存 Cache 实现: CacheAccess

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

共享内存的应用场景

进程间通讯,一般和信号量结合使用比如: TFS 的队列 : tfc::net::CFifoSyncMQ

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

共享内存 :POSIX vs System V

Posix 共享内存与 System V 共享内存区别 :

1. Posix 共享内存区对象的大小可在任何时刻通过调用 ftruncate 修改,而 System V 共享内存区对象的大小是在调用 shmget 创建时固定下来。

System V 共享内存后来被 POSIX 采纳,即现在的 POSIX:XSI 共享内

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

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);

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

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);

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

共享内存使用经验

单进程一般配置使用小于 1.5GB 的共享内存(为什么?)

共享内存一般需要和其它 IPC 配合使用 基于共享内存的 HashMap

基于共享内存的 FIFO 队列 …

共享内存在进程退出后不会丢失,仅在重启后共享内存的数据会丢失( Dump + Binlog 机制可用于备份共享内存中的数据)

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

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]

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

POSIX:XSI 工具

[email protected]:~$ 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

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

管道 :Pipe

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

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

管道 : 匿名管道 (Pipe)

#include <unistd.h>

int pipe(int fildes[2]);

单工模式的管道:fildes[0] 用于从管道中读取数据fildes[1] 用于将数据写入管道

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

管道 : 匿名管道 (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 }

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

管道 : 匿名管道 (Pipe)

当进程调用了 pipe

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

管道 : 匿名管道 (Pipe)

fork 被调用后

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

管道 : 匿名管道 (Pipe)

两个进程分别关闭一个端

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

管道 : 匿名管道 (Pipe)

2 、 管道破裂 : 管道的一端关闭时,

a) 写端关闭,读该管道在所有数据都被读取后, read 返回 0 , 表示达到了文件结束

b) 读端关闭,写该管道产生信号 SIGPIPE

管道的读写

1 、 写管道时,常数 PIPE_BUF 规定了内核中管道缓存器的大小

/usr/include/linux/limits.h:#define PIPE_BUF 4096

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

管道: shell 中的形式cmd1 | cmd2

重定向 cmd > file

管道用于标准输入和标准输出

管道( pipe)

实现代码执行 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);}

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

管道( pipe)

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

popen, pclose: process I/O

#include <stdio.h>

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);

管道( pipe)

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

管道 : 命名管道 (FIFO)

#include <sys/stat.h>

int mkfifo (const char* path, mode_t mode);

int unlink(const char* path) ;

Shell 命令操作: mkfifo 命令 rm 命令

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

管道 : 命名管道 (FIFO)

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

FIFO 的同步和读写

读写 FIFO 时的同步same as pipe

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

管道 : 命名管道 (FIFO)C/S 应用程序

例: client.c, server.c

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

信号量的原理

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

信号量

POSIX:SEM 信号量 #include <semaphore.h>

匿名信号量 命名信号量

POSIX:XSI 信号量集 #include <sys/sem.h>

ipcs & ipcrm 工具

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

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);

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

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);

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

信号量集 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);

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

信号量的使用

1. 使用 System V 的信号量集 可以方便多个信号量的管理,一个信号量集对应一个 sem_key

1. semop 和 semtimedop 操作可能被信号中断, errno == EINTR , 在使用时注意判断下函数返回值并对 EINTR 的情况进行重试

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

课后作业:

要求: 1. 课后作业可个人独立完成 也可 小组协作完成 (小组完成的请注明参与的小组成员)

2. 请注意 编程风格,清晰的实现思路 和 干净整洁的代码 均 会获得适当加分

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

课后作业 1 :基于共享内存的管道

请用 C++ 封装一个类,该类在能够实现基于共享内存的管道功能要求:

1. 当指定的共享内存不存在时,自动创建指定 key 和大小的共享内存 当指定的共享内存存在时,能自动绑定并使用该共享内存 2. 接口

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

课后作业 2 :管道

编写一个程序 ( 程序名 :myls) 包装下 ls 的功能,要求对 ls 的功能做一点

小调整: 当输入 ls –la 时将 total 统计行放到最好一行

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

课后作业 3 :程序设计类

编写一个 斗地主的 出牌仲裁器:1. 规则参考 附件给定的规则

2. 出牌仲裁器必须实现如下场景的功能: 玩家 A 出牌 , 当前轮到玩家 B 出牌,玩家 B 出牌后出牌仲裁器能够判断玩家 B 出的牌是否有效。

3. C++语言实现

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

推荐书目:

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

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

Q&A

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