共享内存与信号量
今天和朋友聊天,他多次提到了共享内存,惭愧的是我没怎么用上,只是从 APUE 等神书阅读到此类名词。这个周末,我来搞懂它们。
共享内存
它是 Linux 最底层的通信机制,被称为最快的通信机制。多个进程共享同一个内存区域实现进程间通信。一个进程创建一个共享内存区域,并将数据存放到共享内存中,而后多个进程对其进行访问。
借鉴网友的例子,我做了注释和修改,一个进程写共享内存 (shmwrite.c),一个进程读共享内存(shmread.c)。
共享内存并未提供同步机制,在第一个进程结束对共享内存的写操作之前,并无自动机制阻止第二个进程开始对它进行读取。上述代码中,我通过自己维护了一个变量 isWritten 来控制同步行为。
还好,伟大的计算机先驱们提供了信号量来帮我们解决同步的问题。
信号量
为了防止出现因多个程序同时访问一个共享资源带来的问题,Linux 使用 信号量协调进程对共享资源的访问的。
信号量只能进行两种操作等待和发送信号,即 P(sv) 和 V(sv).
- P(sv):当sv的值大于零,就减1;当它的值为零,就挂起该进程的执行。
- V(sv):当有其他进程因等待sv而被挂起,就让它恢复运行,当没有进程因等待sv而挂起,就给它加1.
比如:两个进程共享信号量 sv,其中一个进程执行了 P(sv) 操作,它将得到信号量,进入临界区,将 sv 减1。此时sv=0,第二个进程将被阻止进入临界区,它会被挂起以等待第一个进程离开临界区域,并执行 V(sv) 释放信号量,这时第二个进程就可以恢复执行。
mmap 还是 shmget
这两个东西某种程度上很类似。
内存映射,将用户空间的一段内存区域映射到内核空间,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。两者之间需要大量数据传输等操作的话效率是非常高的.
mmap 并不是完全为了用于共享内存而设计的。它提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而 Posix 或系统V的共享内存 IPC 则纯粹用于共享目的.
mmap 使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用 read(),write() 等操作。mmap 并不分配空间, 只是将文件映射到调用进程的地址空间里 然后你就可以用 memcpy 等操作写文件。
附上代码:
- 共享数据结构: shmdata.h
- 读共享内存:shmread.c
- 写共享内存:shmwrite.c