Posix 和 SystemV 的区别

参考:https://blog.csdn.net/derkampf/article/details/60958086
Posix 是“可移植操作系统接口”(Portable Operating System Interface)的首字母缩写。 它并不是一个单一标准,而是一个由电气与电子工程师学会即IEEE开发的一系列标准。 Posix 标准还是由 ISO(国际标准化组织)和 IEC(国际电工委员会)采纳的国际标准,这 两个组织合称为 ISO/IEC。

目前 POSIX 已经成为类 UNIX(Unix-like)操作系统编程的通用接口,极大方便了类 UNIX 环境下应用程序源码级的可移植性。Glibc(GNU C Library),即 C 运行库,是 Linux 系统中最底层的 API,它就是完全按照 POSIX 标准编写的。
System V(System Five),是 Unix 操作系统众多版本中的一支,就是当年UNIX 厂家混战中,比较强大的一个诸侯王,最初由 AT&T 开发,在1983 年第一次发布。一共发行了4个 System V 的主要版本:1、2、3 和 4,比如:System V Release 4,或者称为 SVR4,是最成功的版本,比如现今依然使用的操作系统 SUN Solaris 和 SCO UnixWare,都基于 System V Release 4 的,SUN 公司我想大家都知道吧,依然是现在商用服务器操作系统重要提供商,但是我们常用的 Linux 操作系统并不是基于此的,但是这里要感谢 POSIX 这样标准化的努力,是它兼容了绝大部分 System V 的规格,减少了各类操作系统之间移植的麻烦。
照上面所说的 System V 和 POXIS 是一种应用于系统的接口协议,POXIS 相对于 System V 可以说是比较新的标准,语法相对简单。
在 Linux/Unix 系统编程中支持 System V 和 POXIS。我们常见的一个名词就是POSIX IPC 和 System V IPC。IPC 的全称是 Inter-Process Comminication,就是进程间通信。
由于 SystemV 是早期的标准,POSIX 是标准化后的产物,所以 POSIX 的接口设计更加严谨,除了某些特殊情况下处理不如 SystemV 灵活,但 POSIX 的接口做到了线程安全,而且现在大多数开发都是在 Unix Like(Linux)上,所以推荐 POSIX 标准,如果需要考虑平台的兼容性,就需要具体情况分析了。
接下来先概要性的介绍 POSIX IPC 的概念,其具体使用在其他文章中详述。

POSIX IPC 概念

首先汇总一下所有的 Posix IPC 函数,如下图所示:
image.png
在 POSIX IPC 中,每个 IPC 对象是有名称的,而且名称是一个很重要的概念,Posix IPC 使用 IPC 的名称作为 IPC 的标识。mq_open、sem_open、shm_open 三个函数的第一个参数就是这个名称,这个名称不一定是在文件系统中存在的名称。
Posix IPC 名字必须以一个斜杠开头,但是有个系统不兼容多斜杠(/tmp/)或者根目录(/)下无写权限,就有移植问题。最好的解决方法就是自己定义一个名为 px_ipc_name 的函数,为不同系统的 Posix IPC 名字加上正确的前缀目录。如下程序实例:

  1. //获取当前系统的Posix IPC名字
  2. #define PATH_MAX 16
  3. char *px_ipc_name(const char *name)
  4. {
  5. char *dir, *dst;
  6. const char *slash;
  7. if ((dst = (char *)malloc(PATH_MAX)) == NULL)
  8. return (NULL);
  9. if ((dir = getenv("PX_IPC_NAME")) == NULL)
  10. {
  11. #ifdef POSIX_IPC_PREFIX
  12. dir = POSIX_IPC_PREFIX;
  13. #else
  14. dir = "/tmp/";
  15. #endif
  16. }
  17. slash = (dir[strlen(dir) - 1] == '/') ? "" : "/";
  18. snprintf(dst, PATH_MAX, "%s%s%s", dir, slash, name);
  19. return (dst); //调用者负责释放内存
  20. }

要使用 IPC 对象,需要创建或者打开,这与文件操作类似,主要是使用mq_open、sem_open、shm_open 函数操作。

在创建或者打开 IPC 对象时需要指定操作的 oflag,其常值如下图:
image.png
其中的一些具体含义如下:
O_EXCL 如果该标志和O_CREAT一起指定,那么IPC函数只在所指定名字的消息队 列、信号量或共享内存区对象不存在时才创建新的对象。如果该对象已经存在,而且指定 了O_CREAT | O_EXCL,那么返回一个 EEXIST 错误。
O_NONBLOCK 该标志使得一个消息队列在队列为空时的读或队列填满时的写不被阻塞。
O_TRUNC 如果以读写模式打开了一个已存在的共享内存区对象,那么该标志将使得该对象的长度被截成 0。

IPC 对象是有一定权限的,与文件的权限类似。IPC 对象的存在和创建它这两部必须是原子的。
创建一个消息队列、信号量、共享内存区对象时,需要一个 mode 的参数,指定权限位,由如下所示常值按位或形成的。
image.png
这些常值定义在 头文件中。所指定的权限位受当前进程的文件模式创建掩码修正,该掩码可通过 umask 函数或 shell 的 umask 命令设置。
打开或者创建一个 IPC 逻辑图:
image.png创建或打开一个IPC 对应 oflag 标志:
image.png
注意:如果指定了 O_CREAT 标志但没有指定 O_EXCL 标志的中间那行,无法得到一个指示以判别是创建了一个新对象,还是在引用一个已存在的对象。
**
IPC 的权限位与创建 IPC 类型的每个对象相关联,就像它们与每个 Unix 文件相关联一样。当打开一个已存在的消息队列、信号量或共享内存区对象时(或者未指定O_CREAT,或者指定了O_CREAT但没有指定O_EXCL,同时对象已经存在),将基于如下信息执行权限测试:

  1. 创建时赋予该IPC对象的权限位。
  2. 所请求的访问类型(O_RDONLY、O_WRONLY或O_RDWR)。
  3. 调用进程的有效用户ID、有效组ID以及各个辅助组ID(若支持的话)。

从上面可以看出,当打开一个已存在的 IPC 对象时,所执行的权限测试与打开一个已存在的文件时相似。