TLPI-Chapter 45 System V IPC介绍

栏目: 后端 · 发布时间: 5年前

内容简介:信号量允许多个进程同步它们的动作。一个信号量是一个由内核维护的整数值,它对所有具备相应权限的进程可见。一个进程通过对信号量的值进行相应的修改来通知其他进程它正在执行某个动作。共享内存使得多个进程能够共享内存(即同被映射到多个进程的虚拟内存的页帧)的同一块区域(称为一个端)。由于访问用户空间内存的操作是非常快的,因此共享内存是其中一种速度最快的IPC方法:一个进程一旦更新了共享内存,那么这个变更会立即对共享同一个内存段的其它进程可见。使用ftok函数生成key值,习题45-2是实现ftok()函数,下面的代码

这节开始学习System V IPC,书中后面会介绍POSIX IPC,两者之间的区别可以参考stackoverflow上的一篇回答。 system-v-ipc-vs-posix-ipc

System V IPC包含消息队列、信号量和共享内存。

消息队列

消息队列用来在进程之间传递消息。消息队列与管道有点像,但存在两个重大差异:

第一消息队列是存在边界的,这样读者和写者之间以消息进行通信,而不是通过无分隔符的字节流进行通信。

第二每条消息包括一个整型的type字段,并且可以通过类型选择消息而无需以消息被写入的顺序来读取消息。

信号量

信号量允许多个进程同步它们的动作。一个信号量是一个由内核维护的整数值,它对所有具备相应权限的进程可见。一个进程通过对信号量的值进行相应的修改来通知其他进程它正在执行某个动作。

共享内存

共享内存使得多个进程能够共享内存(即同被映射到多个进程的虚拟内存的页帧)的同一块区域(称为一个端)。由于访问用户空间内存的操作是非常快的,因此共享内存是其中一种速度最快的IPC方法:一个进程一旦更新了共享内存,那么这个变更会立即对共享同一个内存段的其它进程可见。

IPC Key

使用ftok函数生成key值,习题45-2是实现ftok()函数,下面的代码只是ftok函数的使用例子。

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2018.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Solution for Exercise 45-2 */

/* t_ftok.c

   Test the key values returned by ftok(3).

   Usage: t_ftok key-file key-char

   Simply calls ftok(), using the values supplied in the command-line arguments,
   and displays the resulting key.
*/
#include <sys/ipc.h>
#include <sys/stat.h>
#include "tlpi_hdr.h"

int
main(int argc, char *argv[])
{
    key_t key;
    struct stat sb;

    if (argc != 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s file-name keychar\n", argv[0]);

    printf("Size of key_t = %ld bytes\n", (long) sizeof(key_t));

    if (stat(argv[1], &sb) == -1)
        errExit("stat");

    key = ftok(argv[1], argv[2][0]);
    if (key == -1)
        errExit("ftok");

    printf("Key = %lx i-node = %lx st_dev = %lx proj = %x\n",
          (unsigned long) key, (unsigned long) sb.st_ino,
          (unsigned long) sb.st_dev, (unsigned int) argv[2][0]);
    if (key == -1)
        printf("File does not exist\n");

    exit(EXIT_SUCCESS);
}
/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2018.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Listing 45-1 */

/* svmsg_demo_server.c

   Demonstration System V message queue-based server.
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include "tlpi_hdr.h"

#define KEY_FILE "/some-path/some-file"
                                /* Should be an existing file or one
                                   that this program creates */

int
main(int argc, char *argv[])
{
    int msqid;
    key_t key;
    const int MQ_PERMS = S_IRUSR | S_IWUSR | S_IWGRP;   /* rw--w---- */

    /* Optional code here to check if another server process is
       already running */

    /* Generate the key for the message queue */

    key = ftok(KEY_FILE, 1);
    if (key == -1)
        errExit("ftok");

    /* While msgget() fails, try creating the queue exclusively */

    while ((msqid = msgget(key, IPC_CREAT | IPC_EXCL | MQ_PERMS)) ==
            -1) {
        if (errno == EEXIST) {          /* MQ with the same key already
                                           exists - remove it and try again */
            msqid = msgget(key, 0);
            if (msqid == -1)
                errExit("msgget() failed to retrieve old queue ID");
            if (msgctl(msqid, IPC_RMID, NULL) == -1)
                errExit("msgget() failed to delete old queue");
            printf("Removed old message queue (id=%d)\n", msqid);

        } else {                        /* Some other error --> give up */
            errExit("msgget() failed");
        }
    }

    /* Upon loop exit, we've successfully created the message queue,
       and we can then carry on to do other work... */

    printf("Queue created with id %d\n", msqid);

    exit(EXIT_SUCCESS);
}

ipcs和ipcrm命令

ipcs和ipcrm命令是System V IPC领域中类似于ls和rm文件命令的命令。使用ipcs能够获取系统上IPC对象的信息。在默认情况下,ipcs会显示出所有对象,如下面例子所示:

root@52coder:~/tlpi-dist/svipc# ipcs

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x01021263 262144     root       620        0            0           

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      

------ Semaphore Arrays --------
key        semid      owner      perms      nsems

Linux 上,ipcs(1)只显示出拥有读权限的IPC对象的信息,而不管是否拥有这些对象。

ipcrm命令删除一个IPC对象,remove certain IPC resource。
OPTIONS
       -a, --all [shm] [msg] [sem]
              Remove all resources.  When an option argument is provided, the removal is performed only for the specified resource types.  Warning!  Do not
              use -a if you are unsure how the software using the resources might react to missing  objects.   Some  programs  create  these  resources  at
              startup and may not have any code to deal with an unexpected disappearance.

       -M, --shmem-key shmkey
              Remove the shared memory segment created with shmkey after the last detach is performed.

       -m, --shmem-id shmid
              Remove the shared memory segment identified by shmid after the last detach is performed.

       -Q, --queue-key msgkey
              Remove the message queue created with msgkey.

       -q, --queue-id msgid
              Remove the message queue identified by msgid.

       -S, --semaphore-key semkey
              Remove the semaphore created with semkey.

       -s, --semaphore-id semid
              Remove the semaphore identified by semid.

       -V, --version
              Display version information and exit.

       -h, --help
              Display help text and exit.

在/proc/sysvipc/目录下存在msg sem shm分别对应消息队列 信号量和共享内存,与IPC命令不同的是这些文件总是会显示出相应种类的所有对象,不管是否在这些对象上拥有读权限。

总结

System V IPC是首先在System V中被广泛使用的三种IPC机制的名称并且之后被移植到了大多数UNIX实现中以及被加入了各种标准中。这三种IPC机制是允许进程之间交换消息的消息队列,允许进程同步对共享资源的访问的信号量,以及允许两个或更多进程共享内存的同一个页的共享内存。

这三种IPC机制在API和语义上存在很多相似之处。对于每种IPC机制来讲,get系统调用会创建或打开一个对象。给定一个整数key,get调用返回一个整数标识符用来在后续的系统调用中引用对象。每种IPC机制还拥有一个对应的ctl调用用来删除一个对象以及获取和修改对象的关联数据结构中的各种特性。

用来为新IPC对象生成标识符的算法被设计成将(立即)复用同样的标识符的可能性降到最小,即使相应的对象已经被删除了,甚至是使用同样的key来创建新对象也一样。这样客户端服务器与应用程序就能够正常工作了--重新启动的服务器进程能够检测到并删除上一个服务器进程创建的IPC对象,并且这个动作会令上一个服务器进程的客户端所保存的标识符失效。

ipcs命令列出了当前位于系统上的所有System V IPC对象。ipcrm命令用来删除System IPC对象。

在Linux上,/proc/sysvipc目录中的文件可以用来获取系统上所有System V IPC对象的信息。

每种IPC机制都有一组相关的限制,他们通过阻止创建任意数量的IPC对象来避免系统资源的耗尽。/proc/sys/kernel目录中的各个文件可以用来查看和修改这些限制。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法设计与分析

算法设计与分析

屈婉玲、刘田、张立昂、王捍贫 / 清华大学 / 2011-5 / 25.00元

《算法设计与分析》为计算机科学技术专业核心课程“算法设计与分析”教材.全书以算法设计技术和分析方法为主线来组织各知识单元,主要内容包括基础知识、分治策略、动态规划、贪心法、回溯与分支限界、算法分析与问题的计算复杂度、NP完全性、近似算法、随机算法、处理难解问题的策略等。书中突出对问题本身的分析和求解方法的阐述,从问题建模、算法设计与分析、改进措施等方面给出适当的建议,同时也简要介绍了计算复杂性理论......一起来看看 《算法设计与分析》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具