使用 UNIX System V IPC 机制共享应用程序数据( 五 )


关于信号量,要注意的最后一个事项在于,它们被称为建议锁(Advisory Lock) 。这意味着信号量本身并不阻止两个进程同时使用同一个资源;相反,它们旨在建议任何进程自愿询问该资源是否正在使用 。
共享内存空间
共享内存也许是最强大的 SysV IPC 方法,并且此方法最容易实现 。顾名思义,共享内存是在两个进程之间共享一个内存块 。清单 7 显示了一个程序,该程序调用 fork(2) 来将自身划分为一个父进程和一个子进程,两个进程之间使用一个共享内存段进行通信 。
清单 7. 演示共享内存用法的程序
#include
#include
#include
#include
#include
#include
int main(void) {
pid_t pid;
int *shared; /* pointer to the shm */
int shmid;
shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
if (fork() == 0) { /* Child */
/* Attach to shared memory and print the pointer */
shared = shmat(shmid, (void *) 0, 0);
printf("Child pointer %pn", shared);
*shared=1;
printf("Child value=https://www.rkxy.com.cn/dnjc/%dn", *shared);
sleep(2);
printf("Child value=https://www.rkxy.com.cn/dnjc/%dn", *shared);
} else { /* Parent */
/* Attach to shared memory and print the pointer */
shared = shmat(shmid, (void *) 0, 0);
printf("Parent pointer %pn", shared);
printf("Parent value=https://www.rkxy.com.cn/dnjc/%dn", *shared);
sleep(1);
*shared=42;
printf("Parent value=https://www.rkxy.com.cn/dnjc/%dn", *shared);
sleep(5);
shmctl(shmid, IPC_RMID, 0);
}
}
您现在应该已经熟悉传递给 shmget 的参数了:密钥、大小和标志 。此示例中的共享内存大小是单个整数 。清单 7 与前一个示例的不同之处在于它对 IPC 密钥使用了 IPC_PRIVATE 。当使用了 IPC_PRIVATE 时,将保证创建一个唯一的 IPC ID,并且预期应用程序将自己分发该 ID 。在此示例中,父进程和子进程都知道 shmid,因为它们分别是对方的副本 。fork 系统调用创建当前进程的第二个副本,称为子进程,此进程几乎与父进程完全相同 。两个进程的执行都在 fork 之后恢复 。返回值将用于确定当前进程是父进程还是子进程 。
父进程和子进程看起来相似 。首先,shmat 系统调用被用于获得指向共享内存段的指针 。shmat 需要共享内存 ID、一个指针和某些标志 。该指针用于请求特定的内存地址 。通过传递 0,内核可以随心所欲地选择任何内存地址 。标志大部分是特定于供应商的,不过 SHM_RDONLY 是一个公共标志,用于指示不写入的段 。如清单 7 所示,shmat 的常见用法是让内核决定一切 。
shmat 返回一个指向共享内存段的指针,此示例出于调试目的而将其打印到了屏幕上 。然后每个进程依次修改该共享内存段,并打印出值 。最后,父进程使用 shmctl(2) 来删除共享内存段 。清单 8 显示了此程序的输出 。
清单 8. 共享内存示例的输出
sunbox$ ./shared_memory
Child pointer ff390000
Child value=https://www.rkxy.com.cn/dnjc/1
Parent pointer ff380000
Parent value=https://www.rkxy.com.cn/dnjc/1
Parent value=https://www.rkxy.com.cn/dnjc/42
Child value=https://www.rkxy.com.cn/dnjc/42
您可以从输出中看到相同内存空间的共享 。起初,共享内存中的值为 1,这是由子进程设置并由父进程读取的 。然后父进程将该值设置为 42,并由子进程读取 。请注意,父进程和子进程拥有指向共享内存段的不同指针地址,尽管它们是在访问相同的物理内存 。在使用物理地址时,这会导致某些数据结构出现问题,例如链表,因此当您在共享内存中构建复杂结构时,可以使用相对寻址 。

推荐阅读