资源预览内容
第1页 / 共24页
第2页 / 共24页
第3页 / 共24页
第4页 / 共24页
第5页 / 共24页
第6页 / 共24页
第7页 / 共24页
第8页 / 共24页
第9页 / 共24页
第10页 / 共24页
亲,该文档总共24页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
嵌入式Linux操作系统 第6章 进程间通信,www.embedu.org,2,第1章 嵌入式Linux操作系统简介 第2章 Linux操作系统使用与系统配置 第3章 嵌入式Linux编程环境 第4章 存储管理 第5章 操作系统进程 第6章 进程间通信 第7章 中断与系统调用 第8章 文件管理 第9章 设备管理 第10章 嵌入式Linux的构建,课程安排:,www.embedu.org,3,第6章 进程间通信 6.1 什么是进程间通信 6.2 互斥与同步 6.3 信号量 6.4 共享内存 6.5 消息队列 6.6 管道 思考题,本章课程:,www.embedu.org,4,6.1 什么是进程间通信,进程间通信(IPC)就是为了解决这些问题而提出的特有机制,它们为多任务系统提供了不同进程的通信机制,同时也提供了对于临界资源和共享资源的保护。 进程间通信的主要目的是实现同一计算机系统内部的相互协作的进程之间的数据共享与信息交换,由于这些进程处于同一软件和硬件环境下,利用操作系统提供的编程接口,用户可以方便地在程序中实现这种通信;应用程序间通信的主要目的是实现不同计算机系统中的相互协作的应用程序之间的数据共享与信息交换,由于应用程序分别运行在不同计算机系统中,它们之间要通过网络之间的协议才能实现数据共享与信息交换。,www.embedu.org,5,6.1 什么是进程间通信,程序和进程 最初Unix IPC包括:管道、FIFO、信号; System V IPC包括:System V消息队列、 System V信号灯、System V共享内存区; Posix IPC包括: Posix消息队列、Posix信号灯、Posix共享内存区。 进程间通信,主要有两种方式:虚拟内存系统中的进程间通信和Falt 内存系统中的进程间通信。 UCOS是比较典型的Falt 内存系统,它不支持虚拟内存机制,也没有用户空间和内核空间的区别,实际上它就类似Linux的内核空间,不同任务间可以相互访问,没有不同进程间内存保护机制。所以可以完全利用Linux系统中的同一进程中不同线程的通信机制。由于所有的任务与中断都共享同一地址空间,所以同步机制也与任务间通信在同一空间中实现,是这两种机制的相互替换成为可能。 Windows作为一种复杂的多任务系统,也提供了多种进程间通信方式,包括:文件映射、共享内存、匿名管道、命名管道、邮件槽、剪贴板、动态数据交换(DDE)、对象连接与嵌入(OLE)、动态连接库(DLL)、远程过程调用(RPC)、NetBios函数、Sockets、WM_COPYDATA消息。,www.embedu.org,6,6.2 互斥与同步,互斥与同步是进程间通信中非常重要的一对概念,也是相交进程之间的两种主要关系。在嵌入式操作系统开发中经常会遇到同步、互斥的问题,如果处理得不好,程序就会出现很多意想不到的结果。而在多处理器之间、ISR与ISR之间、ISR与任务之间、任务与任务之间都可能需要互斥与同步。例如不同任务优先级的抢占,中断处理等。 互斥和同步是两个紧密相关而又容易混淆的概念。所谓互斥,是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。两个互斥的进程,只能等到前一个进程运行完后,下一个进程才能运行。所谓同步,是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。 同步是一种更为复杂的互斥,而互斥是一种特殊的同步。 原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。,www.embedu.org,7,6.2 互斥与同步,原子类型定义如下: typedef struct volatile int counter; atomic_t; 有关原子操作: #define atomic_inc_not_zero(v) atomic_add_unless(v), 1, 0) #define atomic_add(i, v) (void) atomic_add_return(i, v) #define atomic_inc(v) (void) atomic_add_return(1, v) #define atomic_sub(i, v) (void) atomic_sub_return(i, v) #define atomic_dec(v) (void) atomic_sub_return(1, v) #define atomic_inc_and_test(v) (atomic_add_return(1, v) = 0) #define atomic_dec_and_test(v) (atomic_sub_return(1, v) = 0) #define atomic_inc_return(v) (atomic_add_return(1, v) #define atomic_dec_return(v) (atomic_sub_return(1, v) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) = 0) #define atomic_add_negative(i,v) (atomic_add_return(i, v) 0),www.embedu.org,8,6.3 信号量,6.3.1 什么是信号量 信号量是最早出现的用来解决进程同步与互斥问题的机制,包括一个称为信号量的变量及对它进行的两个原语操作,为P、V操作。 信号量可以用来保护两个或多个关键代码段,这些关键代码段不能并发调用。在进入一个关键代码段之前,线程必须获取一个信号量。如果关键代码段中没有任何线程,那么线程会立即进入该框图中的那个部分。一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。,www.embedu.org,9,6.3 信号量,6.3.2 信号量的内核实现 Linux内核的信号量在概念和原理上与用户态的System V的IPC机制信号量是一样的,但是它只能在内核空间使用。信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为1就变成互斥锁(Mutex),即同时只能有一个任务可以访问信号量保护的共享资源。当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此它也唤醒所有等待该信号量的任务。 在Linux内核源码的kernel/printk.c中,使用宏DECLARE_MUTEX声明了一个互斥锁console_sem,它用于保护console驱动列表console_drivers以及同步对整个console驱动系统的访问。,www.embedu.org,10,6.3 信号量,6.3.2 信号量的内核实现 信号量数据结构定义在include/asm-i386/semaphore.h中: struct semaphore spinlock_t lock; unsigned int count; struct list_head wait_list; ; 其中wait _list字段存放当前等待该信号量的所有进程的链表。如果count大于或等于0,该链表就为空。 与信号量相关的内核实现还包括sema_init函数,val表示信号量的初始值: static inline void sema_init(struct semaphore *sem, int val) static struct lock_class_key _key; *sem = (struct semaphore) _SEMAPHORE_INITIALIZER(*sem, val); lockdep_init_map( #define init_MUTEX(sem) sema_init(sem, 1) #define init_MUTEX_LOCKED(sem) sema_init(sem, 0),www.embedu.org,11,6.3 信号量,6.3.3 信号量的使用 信号量的使用通常有四个步骤,分别是: DECLARE_MUTEX(sem); down( /释放信号量 与信号量相关的内核API,www.embedu.org,12,6.3 信号量,6.3.3 信号量的使用 读写信号量的API,www.embedu.org,13,6.4 共享内存,6.4.1 什么是共享内存 共享内存是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。 用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据1:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。,www.embedu.org,14,6.4 共享内存,6.4.1 什么是共享内存 在Linux操作系统中,内核做两件事:一件是在内存中规划出一块区域来作为共享区,另一件事就是把这个区域映射到参与通信的各个进程空间。具体做法是把一个已打开的文件所占用的内存空间来作为共享区,然后通过调用mmap()把这块区域映射到各个进程地址空间,从而使用户进程都可以看到这个共享区域。 mmap原型: void *mmap(void * start, size_t len, int prot, int flags, int fd, off_t offset); 其中,参数fd用来指定被映射的文件;offset指定映射的起始位置偏移量;len指定文件被映射部分的长度;start用来指定映射到虚拟地址空间的起始地址。,www.embedu.org,15,6.4 共享内存,6.4.2 共享内存的内核实现 一个共享内存区由多个共享段组成,用来描述一个共享内存段的内核数据结构是shmid_kernel,这个结构在includelinuxshm.h中定义 struct shmid_kernel /* private to the kernel */ struct kern_ipc_perm shm_perm; /描述进程间通信许可的结构 struct file * shm_file; /指向共享内存页交换文件对象指针 unsigned long shm_nattch; /挂接到本段共享内存的进程数 unsigned long shm_segsz; /段大小 time_t shm_atim; /最后挂接时间 time_t shm_dtim; /最后解除挂接时间 time_t shm_c
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号