消息队列、共享内存和信号量有很多相同的地方,所以统称它们为XSI IPC[2]。相同的地方有:(1) 每一个IPC structure(message queue,semaphores,or shared memory segment) in the kenel is referred to by a non-negative integer identifier。identifier是IPC structure的内部名字,对于其他进程来说,是不可见的,所以还要有一个key充当IPC structure的外部名字。Linux下key的数据类型是key_t(定义在 ),是个long integer。(2) 三种IPC都有一些限制,在Linux下使用ipcs -l查看。(3)三种IPC的数据结构的第一个元素是结构类型ipc_perm,它存储有关权限的信息。
共享内存是最快的一种IPC(不只是在XSI IPC中比较)。
1. XSI IPC与pipe、FIFOs比较
XSI IPC are systemwide and do not have a reference count,若没有使用相应的函数删除XSI IPC,创建和使用它们的进程都终止后,XSI IPC还在系统中。Compare this with a pipe, which is completely removed when the last process to reference it terminates. With a FIFO, although the name stays in the file system until explicitly removed, any data left in a FIFO is removed when the last process reference the FIFO terminates.
XSI IPC are not knowed by names in the file system, 也就不使用file descriptor,所以不能像pipe和FIFO那样,可以使用read、open等FILE I/O。XSI IPC需要增加新的函数,提高了复杂性。
2. 《APUE》书建议:learn pipes and FIFOs, since these two basic technicals can still be used effectively in numerous applications. Avoid using message queues and semaphores in any new applications. Full-duplex pipes and record locking should be considered instead, as they are far simpler. Shared memory still has its use, although the same functionality can be provided through the use of the mmap function. The mmap function can be used to map portions of a file into the address space of a process.
3. 消息队列、信号量和共享内存的数据结构和函数很相似,所以下面只列出共享内存的数据结构和函数
内核为共享内存维护的数据结构至少有如下元素(具体的操作系统实现会增加一些元素):
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz; //size of segment in bytes
pid_t shm_lpid;//pid of last shmop()
pid_t shm_cpid; //pid of create
shmatt_t shm_nattch;//number of current attaches
time_t shm_atime; //last-attach time
time_t shm_dtime; //last-detach time
time_t shm_ctime; //last-change time
};
提供的函数有:
#include
//obtain a shared memory identifier
int shmget(key_t key, size_t size,
int flag);
//variaous shared memory operations
int shmctl(
int shmid,
int cmd,
struct shmid_ds *buf);
//attach shared memory to address space
void *shmat(
int shmid,
const
void *addr,
int flag);
//detach shared memory
int shmdt(
void *addr);
共享内存attach到进程地址空间的什么地方?实验得出是在栈下堆上,实验代码:
int shmid;
printf("&shmid is %lx/n", &shmid);
char* ptr =(char*)malloc(MALLOC_SIZE);
printf("malloced from %lx to %lx/n", (unsigned long)ptr,
(unsigned long)ptr + MALLOC_SIZE);
shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE);
shmptr = shmat(shmid, 0, 0);
printf("shared memory attached from %lx to %lx/n", (unsigned long)
shmptr, (unsigned long)shmptr + SHM_SIZE);
shmctl(shmid, IPC_RMID, 0);
注:Intel-based的Linux系统。
参考资料
[1] 《UNIX网络编程第二卷:进程间通信》
[2] 《APUE》