SHM_OPEN - Linux手册页

时间:2019-08-20 18:01:18  来源:igfitidea点击:

Linux程序员手册 第3部分
更新日期: 2020-04-11

名称

shm_open,shm_unlink-创建/打开或取消链接POSIX共享内存对象

语法

#包括
#include / 用于模式常量/
#include / *对于O_ 常量/

int shm_open(const char * name,int oflag,mode_t模式);

int shm_unlink(const char * name);

与-lrt链接。

说明

shm_open()创建并打开一个新的,或打开一个现有的POSIX共享内存对象。 POSIX共享内存对象实际上是一个句柄,不相关的进程可以使用它来对共享内存的同一区域进行mmap(2)。 shm_unlink()函数执行相反的操作,删除先前由shm_open()创建的对象。

shm_open()的操作类似于open(2)的操作。名称指定要创建或打开的共享内存对象。对于可移植的用途,共享内存对象应使用/ somename形式的名称来标识;也就是说,一个以NULL结尾的字符串,最多NAME_MAX(即255个)字符,由一个初始斜杠组成,后跟一个或多个字符(都不是斜杠)。

oflag是通过将O_RDONLY或O_RDWR中的一个与此处列出的其他任何一个标志进行正或运算而创建的位掩码:

O_RDONLY
打开对象以进行读取访问。以这种方式打开的共享内存对象只能被mmap(2)进行读取(PROT_READ)访问。
O_RDWR
打开对象以进行读写访问。
O_CREAT
如果共享内存对象不存在,请创建它。对象的用户和组所有权来自调用过程的相应有效ID,并且对象的许可权位是根据模式的低9位来设置的,除了那些在进程文件模式创建掩码中设置的位(请参见umask(2))已针对新对象清除。 open(2)中列出了一组可用于定义模式的宏常量。 (可以通过包含。获得这些常量的符号定义。)
新的共享内存对象最初的长度为零-可以使用ftruncate(2)设置对象的大小。共享内存对象新分配的字节将自动初始化为0。
O_EXCL
如果还指定了O_CREAT,并且已经存在具有给定名称的共享内存对象,则返回错误。自动检查对象是否存在以及是否创建对象(如果不存在)。
O_TRUNC
如果共享内存对象已经存在,请将其截断为零字节。

这些标志值的定义可以通过包含来获得。

成功完成后,shm_open()将返回一个新文件描述符,该文件描述符引用共享内存对象。该文件描述符保证是该进程中先前未打开的编号最小的文件描述符。为文件描述符设置了FD_CLOEXEC标志(请参见fcntl(2))。

文件描述符通常在对ftruncate(2)(对于新创建的对象)和mmap(2)的后续调用中使用。调用mmap(2)之后,可以关闭文件描述符,而不会影响内存映射。

shm_unlink()的操作类似于unlink(2):它将删除共享内存对象名称,并且一旦所有进程都取消了对象的映射,便会取消分配并销毁关联内存区域的内容。成功执行shm_unlink()之后,尝试对具有相同名称的对象进行shm_open()会失败(除非指定了O_CREAT,在这种情况下会创建一个新的,不同的对象)。

返回值

成功时,shm_open()返回文件描述符(非负整数)。失败时,shm_open()返回-1。 shm_unlink()成功返回0,错误返回-1。

错误说明

失败时,将设置errno以指示错误原因。 errno中可能出现的值包括:

EACCES
拒绝共享内存对象shm_unlink()的权限。
EACCES
在指定模式下,对shm_open()名称的权限被拒绝,或者指定了O_TRUNC,并且调用者对该对象没有写权限。
EEXIST
O_CREAT和O_EXCL都已指定给shm_open(),并且已存在由名称指定的共享内存对象。
EINVAL
shm_open()的名称参数无效。
EMFILE
已达到打开文件描述符数量的每个进程限制。
ENAMETOOLONG
名称的长度超过了PATH_MAX。
ENFILE
已达到系统范围内打开文件总数的限制。
ENOENT
试图shm_open()一个不存在的名称,并且未指定O_CREAT。
ENOENT
试图给shm_unlink()一个不存在的名称。

版本

这些功能在glibc 2.2及更高版本中提供。

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
shm_open(),shm_unlink()Thread safetyMT-Safe locale

遵循规范

POSIX.1-2001,POSIX.1-2008。

POSIX.1-2001说,新创建的共享内存对象的组所有权设置为调用进程的有效组ID或"系统默认组ID"。 POSIX.1-2008说,可以将组所有权设置为调用进程的有效组ID,或者,如果对象在文件系统中可见,则可以将其设置为父目录的组ID。

备注

POSIX未指定O_RDONLY和O_TRUNC组合的行为。在Linux上,这将成功截断现有的共享内存对象-在其他UNIX系统上可能不是这样。

Linux上的POSIX共享内存对象实现利用通常安装在/ dev / shm下的专用tmpfs(5)文件系统。

示例

下面的程序使用POSIX共享内存和POSIX未命名信号量来交换数据。 "反弹"程序(必须首先运行)引发字符串的情况,该字符串由"发送"程序放置到共享内存中。修改数据后,"发送"程序将打印修改后的共享内存的内容。这两个程序的示例执行如下:

$ ./pshm_ucase_bounce /myshm &
[1] 270171
$ ./pshm_ucase_send /myshm hello
HELLO

下面提供了有关这些程序的更多详细信息。

Program source: pshm_ucase.h

以下两个程序都包含以下头文件。它的主要目的是定义一个结构,该结构将施加在两个程序之间共享的内存对象上。

#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

#define BUF_SIZE 1024   /* Maximum size for exchanged string */

/* Define a structure that will be imposed on the shared
   memory object */

struct shmbuf {
    sem_t  sem1;            /* POSIX unnamed semaphore */
    sem_t  sem2;            /* POSIX unnamed semaphore */
    size_t cnt;             /* Number of bytes used in aqbufaq */
    char   buf[BUF_SIZE];   /* Data being transferred */
};

Program source: pshm_ucase_bounce.c

" bounce"程序使用其命令行参数中给出的名称创建一个新的共享内存对象,并调整对象大小以匹配头文件中定义的shmbuf结构的大小。然后,它将对象映射到进程的地址空间,并将对象内部的两个POSIX信号量初始化为0。

在"发送"程序发布第一个信号量之后,"反弹"程序将通过"发送"程序放置在内存中的数据大写,然后发布第二个信号量以告知"发送"程序:它现在可以访问共享内存。

/* pshm_ucase_bounce.c

   Licensed under GNU General Public License v2 or later.
*/
#include <ctype.h>
#include "pshm_ucase.h"

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s /shm-path\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    char *shmpath = argv[1];

    /* Create shared memory object and set its size to the size
       of our structure */

    int fd = shm_open(shmpath, O_CREAT | O_EXCL | O_RDWR,
                      S_IRUSR | S_IWUSR);
    if (fd == -1)
        errExit("shm_open");

    if (ftruncate(fd, sizeof(struct shmbuf)) == -1)
        errExit("ftruncate");

    /* Map the object into the calleraqs address space */

    struct shmbuf *shmp = mmap(NULL, sizeof(struct shmbuf),
                               PROT_READ | PROT_WRITE,
                               MAP_SHARED, fd, 0);
    if (shmp == MAP_FAILED)
        errExit("mmap");

    /* Initialize semaphores as process-shared, with value 0 */

    if (sem_init(&shmp->sem1, 1, 0) == -1)
        errExit("sem_init-sem1");
    if (sem_init(&shmp->sem2, 1, 0) == -1)
        errExit("sem_init-sem2");

    /* Wait for aqsem1aq to be posted by peer before touching
       shared memory */

    if (sem_wait(&shmp->sem1) == -1)
        errExit("sem_wait");

    /* Convert data in shared memory into upper case */

    for (int j = 0; j < shmp->cnt; j++)
        shmp->buf[j] = toupper((unsigned char) shmp->buf[j]);

    /* Post aqsem2aq to tell the to tell peer that it can now
       access the modified data in shared memory */

    if (sem_post(&shmp->sem2) == -1)
        errExit("sem_post");

    /* Unlink the shared memory object. Even if the peer process
       is still using the object, this is okay. The object will
       be removed only after all open references are closed. */

    shm_unlink(shmpath);

    exit(EXIT_SUCCESS);
}

Program source: pshm_ucase_send.c

"发送"程序带有两个命令行参数:先前由"反弹"程序创建的共享内存对象的路径名,以及要复制到该对象中的字符串。

该程序将打开共享内存对象,并将该对象映射到其地址空间。然后,它将其第二个参数中指定的数据复制到共享内存中,并发布第一个信号量,该信号量告诉" bounce"程序现在可以访问该数据了。在" bounce"程序发布第二个信号量之后," send"程序在标准输出上打印共享内存的内容。

/* pshm_ucase_send.c

   Licensed under GNU General Public License v2 or later.
*/
#include <string.h>
#include "pshm_ucase.h"

int
main(int argc, char *argv[])
{
    if (argc != 3) {
        fprintf(stderr, "Usage: %s /shm-path string\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    char *shmpath = argv[1];
    char *string = argv[2];
    size_t len = strlen(string);

    if (len > BUF_SIZE) {
        fprintf(stderr, "String is too long\n");
        exit(EXIT_FAILURE);
    }

    /* Open the existing shared memory object and map it
       into the calleraqs address space */

    int fd = shm_open(shmpath, O_RDWR, 0);
    if (fd == -1)
        errExit("shm_open");

    struct shmbuf *shmp = mmap(NULL, sizeof(struct shmbuf),
                               PROT_READ | PROT_WRITE,
                               MAP_SHARED, fd, 0);
    if (shmp == MAP_FAILED)
        errExit("mmap");

    /* Copy data into the shared memory object */

    shmp->cnt = len;
    memcpy(&shmp->buf, string, len);

    /* Tell peer that it can now access shared memory */

    if (sem_post(&shmp->sem1) == -1)
        errExit("sem_post");

    /* Wait until peer says that it has finished accessing
       the shared memory */

    if (sem_wait(&shmp->sem2) == -1)
        errExit("sem_wait");

    /* Write modified data in shared memory to standard output */

    write(STDOUT_FILENO, &shmp->buf, len);
    write(STDOUT_FILENO, "\n", 1);

    exit(EXIT_SUCCESS);
}

另外参见

close(2),fchmod(2),fchown(2),fcntl(2),fstat(2),ftruncate(2),memfd_create(2),mmap(2),open(2),umask(2), shm_overview(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/