精华内容
下载资源
问答
  • shell 共享内存
    2019-09-05 12:03:46

    删除系统中,所有的[共享内存、信号量、消息队列]

    #!/bin/bash
    
    for i in `ipcs -m | tail -n +4 | awk {'print $2'}` # 共享内存
    do
    	ipcrm -m $i;
    	echo 删除shm = $i
    done
    
    for i in `ipcs -s | tail -n +4 | awk {'print $2'}` # 信号量
    do
    	echo 删除sem = $i
    	ipcrm -s $i;
    done
    
    for i in `ipcs -q | tail -n +4 | awk {'print $2'}` # 消息队列
    do
    	echo 删除mq = $i
    	ipcrm -q $i;
    done
    
    
    更多相关内容
  • Linux共享内存实现机制的详解内存共享: 两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块...

    Linux共享内存实现机制的详解

    内存共享: 两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。

    22f9c9f3ed2c12dc2f4842aa7ab920fd.png

    效率: 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]: 一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建 立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回 文件的。因此,采用共享内存的通信方式效率是非常高的。

    共享内存实现机制

    共享内存是通过把同一块内存分别映射到不同的进程空间中实现进程间通信。而共享内存本身不带任何互斥与同步机制,但当多个进程同时对同一内存进行读写操作时会破坏该内存的内容,所以,在实际中,同步与互斥机制需要用户来完成。

    来看几个系统调用函数:

    (1)创建共享内存

    677c23d3d4dcbd8e931ecd22ccfe63c8.png

    参数:key为输出型参数

    size:size的大小应为1024整数倍(4k对齐)

    shmflg:权限标志

    (2)将共享内存映射到自己的内存空间:shmat

    shmat是空间映射,通过创建的共享内存,在它能被进程访问之前,需要把该段内存映射到用户进程空间。shmaddr是用来指定共享内存映射到当前进程中的地址位置,要想改设置有用,shmflag必须设置为SHM_RND标志。大多情况下,应设置为空指针(void*)0,让系统自动选择地址,从而减小程序对硬件的依赖性。shmflag除了上面的设置外,还可以设置为SHM_RDONLY,使得映射过来的地址只读。

    返回值:调用成功则返回映射地址的第一个字节,失败返回-1。

    (3)解除映射:shmdt

    1af36c08f5a7681afb94b287f97fa71b.png

    参数为要解除的地址空间。

    (4)控制共享内存

    ac1551f71d535c79ffac8e61d95eecfe.png

    先来看第三个参数的结构体:

    98ca82ef21c165f62fa246aeef00e152.png

    19911246b6468bc5c49c8aebdebd052d.png

    第二个参数cmd的选项:IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构体复制到buf里

    IPC_SET:改变共享内存的状态,把buf所指的结构体中的uid,gid,mode,复制到共享内存的shmid_ds结构体内

    IPC_RMID:删除这块共享内存

    BUF:共此内存管理结构体

    代码实现:

    531ffd225724b443ad97c7f9e1f5c6b8.png

    a2b16ae04615181b749bbcae3826e5ca.png

    31844271acdf77c68889140644f190be.png

    共享内存的特点:

    (1)共享内存就是允许两个不想关的进程访问同一个内存

    (2)共享内存是两个正在运行的进程之间共享和传递数据的最有效的方式

    (3)不同进程之间共享的内存通常安排为同一段物理内存

    (4)共享内存不提供任何互斥和同步机制,一般用信号量对临界资源进行保护。

    (5)接口简单

    所有进程间通信的特点:

    (1)管道

    管道分为命名管道和匿名管道。匿名管道只能单向通信,且只能在有亲缘关系的进程间使用,常用于父子进程,当一个进程创建了一个管道,并调用fork创建子进程后,父进程关闭读端,子进程关闭写端,实现单向通信。管道是面向字节流,自带互斥与同步机制,生命周期随进程。

    命名管道与匿名管道:命名管道允许毫不相干的两个进程之间

    (2)信号量

    信号量是一个计数器,可以用来控制多个线程对共享资源的访问,它不是用于交换大批数据,而用于多线程之间的同步,常作为一种锁机制,防止某进程在访问资源时其他进程也来访问,因此,主要作为进程间以及同一进程的不同线程间的同步手段。

    (3)消息队列

    消息队列是消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区受限等特点。消息队列是UNIX下不同进程之间可以实现资源共享的 一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程,对消息队列具有操作权限的进程都可以使用msgget完成对消息队列的操作控制,通过使用消息类型,进程可以按顺序读信息,或为消息安排优先级顺序。

    (4)共享内存

    共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式,它是针对其他IPC方式运行效率低而专门设计的,它往往与其他机制,如信号量,配合使用,来实现进程间的同步。

    以上就是Linux共享内存实现机制的内容详细介绍,大家可以参考下,如果有疑问的可以到本站留言,进行讨论。感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

    展开全文
  • 您可使用shell命令来查看与释放已经分配的共享内存,下面将详细说明如何进行查看和释放分配的共享内存的方法。python预备知识Linux中经过API函数shmget建立的共享内存通常都是在程序中使用shmctl来释放的,可是有时...

    在使用共享内存的程序异常退出时,因为没有释放掉共享内存,在调试时会出现错误。您可使用shell命令来查看与释放已经分配的共享内存,下面将详细说明如何进行查看和释放分配的共享内存的方法。python

    预备知识

    Linux中经过API函数shmget建立的共享内存通常都是在程序中使用shmctl来释放的,可是有时为了调试程序,开发人员可能经过Ctrl + C等方式发送中断信号来结束程序,此时程序申请的共享内存就不能获得释放,固然若是程序没有改动的话,从新运行程序时仍然会使用上次申请的共享内存,可是若是咱们修改了程序,因为共享内存的大小不一致等缘由会致使程序申请共享内存错误。所以,咱们老是但愿每次结束时就能释放掉申请的共享内存。linux

    有两种方法能够用来释放共享内存:shell

    第一种:若是老是经过Crtl+C来结束的话,能够作一个信号处理器,当接收到这个信号的时候,先释放共享内存,而后退出程序。app

    第二种:无论你以什么方式结束程序,若是共享内存仍是得不到释放,那么能够经过linux命令ipcrm shm shmid来释放,在使用该命令以前能够经过ipcs -m命令来查看共享内存。函数

    共享内存查看

    使用ipcs命令,不加如何参数时,会把共享内存、信号量、消息队列的信息都打印出来,若是只想显示共享内存信息,使用以下命令:调试

    [root@localhost ~]# ipcs -morm

    ------ Shared Memory Segments --------队列

    key shmid owner perms bytes nattch status 进程

    0x00000000 1867776 root 600 393216 2 dest ip

    0x00000000 1900545 root 600 393216 2 dest

    0x00030021 1703938 zc 666 131104 1

    0x0003802e 1736707 zc 666 131104 1

    0x00030004 1769476 zc 666 131104 1

    0x00038002 1802245 zc 666 131104 1

    0x00000000 1933318 root 600 393216 2 dest

    0x00000000 1966087 root 600 393216 2 dest

    0x00000000 1998856 root 600 393216 2 dest

    0x00000000 2031625 root 600 393216 2 dest

    0x00000000 2064394 root 600 393216 2 dest

    0x0014350c 2261003 cs 666 33554432 2

    0x00000000 2129932 root 600 393216 2 dest

    0x00000000 2162701 root 600 393216 2 dest

    0x00143511 395837454 root 666 1048576 1

    其中:

    第一列就是共享内存的key;

    第二列是共享内存的编号shmid;

    第三列就是建立的用户owner;

    第四列就是权限perms;

    第五列为建立的大小bytes;

    第六列为链接到共享内存的进程数nattach;

    第七列是共享内存的状态status。其中显示“dest”表示共享内存段已经被删除,可是还有用户在使用它,当该段内存的mode字段设置为SHM_DEST时就会显示“dest”。当用户调用shmctl的IPC_RMID时,内存先查看多少个进程与这个内存关联着,若是关联数为0,就会销毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,若是全部进程都不用则删除这段共享内存。

    共享内存释放

    要释放共享内存,须要使用ipcrm命令,使用shmid做为参数,shmid在ipcs命令中会有输出,下面的命令能够释放全部已经分片的共享内存:

    # ipcrm

    # ipcs -m | awk ‘$2 ~/[0-9]+/ {print $2}’ | while read s; do sudo ipcrm –m $s; done

    注:Linux中vi使用Ctrl+s来锁定,须要使用Ctrl+q来解除锁定。

    使用Python编写的rmsharemem.py脚本以下:

    # -*- coding: utf-8 -*-

    # Remove the share memory

    import os

    import sys

    import getopt

    def usage():

    print "usage: python rmsharemem.py -h -o -s size "

    print " -h show help information"

    print " -o the owner create share memory need to delete"

    print " -s the share memory size"

    print " the shmid list need to delete"

    def getsharemem():

    sharemap = {}

    fp = os.popen('ipcs -m')

    lines = fp.readlines()

    for l in lines:

    if not l.startswith('0x'):

    continue

    s = l.split()

    if sharemap.has_key(s[2]):

    sharemap[s[2]].append(s)

    else:

    sharemap[s[2]] = [s]

    #print 'Share memory map:\n', sharemap

    return sharemap

    if __name__ == "__main__":

    opts, args = getopt.getopt(sys.argv[1:], "o:hs:")

    # opts is the parameter with options

    # args is the parameter no ptions

    owner = None

    size = 0

    for o, p in opts:

    if o == '-h':

    usage()

    sys.exit(0)

    elif o == '-o':

    owner = p

    elif o == '-s':

    size = p

    if not owner:

    val = raw_input("Are you sure to remove all share memory?(yes/no)");

    if (val <> "yes"):

    usage()

    sys.exit(0)

    count = 0

    total = 0

    if len(args) > 0:

    for shmid in args:

    cmd = 'ipcrm -m %s' % shmid

    print 'execute command: %s' % cmd

    ret = os.system(cmd)

    total += 1

    if ret == 0:

    count += 1

    print 'remove %s shared memory success' % shmid

    else:

    print 'remove %s shared memory failed' % shmid

    else:

    shmmap = getsharemem()

    for o, l in shmmap.items():

    if owner and o <> owner:

    continue

    for p in l:

    total += 1

    if size and size <> p[4]:

    continue

    cmd = 'ipcrm -m %s' % p[1]

    print 'execute command: %s' % cmd

    ret = os.system(cmd)

    if ret == 0:

    count += 1

    print 'remove %s shared memory success' % p[1]

    else:

    print 'remove %s shared memory failed' % p[1]

    print 'total share memory number = %s' % total

    print 'remove success number = %s' % count

    sys.exit(0)

    共享内存大小修改

    使用下面的命令查看共享内存的大小:

    # cat /proc/sys/kernel/shmmax

    修改共享内存大小:

    临时修改:在root用户下执行# echo 268435456 > /proc/sys/kernel/shmmax把共享内存大小设置为256MB;

    永久修改:在root用户下修改/etc/rc.d/rc.local文件,加入下面一行:

    echo 268435456 > /proc/sys/kernel/shmmax

    便可每次启动时把共享内存修改成256MB。

    展开全文
  • 共享内存2.1 创建/打开共享内存2.1.1 shmget 函数2.1.2 ftok 函数2.2 关联和解除关联2.2.1 shmat 函数2.2.2 shmdt 函数2.3 删除共享内存2.3.1 shmctl 函数2.3.2 相关shell命令2.3.3 共享内存状态2.4 进程间通信2.5 *...

    内存映射 及 共享内存

    1.内存映射(mmap)

    推荐B站的大丙老师,讲课很干货

    1.1 创建内存映射区

    如果要实现进程间通信,可以通过函数创建一块内存映射区 ,和管道不同的是管道对应的内存空间在内核中,而内核映射区对应的内存空间在进程的用户区(用于加载动态库的区域),及进程通信使用的内存映射区不是一块,而是在每个进程内部都有一块

    每个进程的地址空间是独立的,各个进程之间也不能直接访问其他地址的内存映射区,需要通信的进程需要将各自的内存映射区和同一磁盘文件进行映射 ,这样进程之间就可以通过磁盘文件这个唯一的桥梁完成数据的交互。

    在这里插入图片描述

    小结:

    磁盘文件数据可以完全加载到进程的内存映射区也可以部分加载到进程的内存映射区,当进程A中的内存映射区数据被修改了,数据会自动同步到磁盘文件,同时和磁盘文件建立映射关系的其他进程内存映射区中的数据也会和磁盘文件进行数据实时同步,该同步机制保证了各进程之间的数据共享;

    使用内存映射区可以使无论有无血缘关系的进程间通信

    #include <sys/mman.h>
    //创建内存映射区
    void *mmap(void *addr , size_t length , int port , int flags , int fd , off_t offset);
    

    参数:

    • addr: 从动态库加载区的具体位置开始创建内存映射区,默认为NULL,委托内核分配;

    • length: 创建内存映射区的大小(字节),实际上按照4k的整数倍分配;

    • port: 对内存映射区的操作权限;

    1. PROT_READ : 读内存映射区;
    2. PROT_WRITE : 写内存映射区;
    3. PROT_READ | PROT_WRITE : 读写权限;

    flags:

    1. MAP_SHARED : 多个进程可以共享数据,进行映射数据同步;
    2. MAP_PRIVATE : 映射区是私有的,不能同步给其他进程;

    fd: 文件描述符,对应一个打开的磁盘文件,内存映射区通过该文件描述符和磁盘文件建立关联;

    offset: 磁盘文件的偏移量,文件从偏移的位置开始进行数据映射,使用这个参数需要注意:

    1. 偏移量必须大于4k的整数倍 , 写0代表不偏移;
    2. 这个参数必须是大于0的;

    返回值:

    成功: 返回一个内存映射区的其实地址;

    失败: MAP_FAILED(that is ,(void*)-1)

    mmap () 函数的参数相对较多,在使用该函数创建用于进程间通信的内存映射区的时候,各参数的指定都有一些注意事项,具体如下:

    /*
    1. 第一个参数:addr 指定 NULL
    2. 第二个参数:length 必须要 >0
    3. 第三个参数: port ,进程间通信需要对内存映射区有读写权限:PORT_READ|PORT_WRITE
    4. 第四个参数:flags,如果需要进程通信,指定:MAP_SHARED
    5. 第五个参数:fd,打开的文件必须大于0,进程间通信需要文件操作权限和映射区操作权限相同
                               内存映射区创建成功之后,关闭这个文件描述符不会影响进程间通信;
    6. 第六个参数:offset ,不偏移指定为0,如果偏移必须是4k的整数倍;
    */ 
    

    内存映射区使用完之后也需要释放,释放函数原型:

    int munmap(void *addr,size_t length);
    

    参数:

    addr: mmap()的返回值,创建内存映射区的起始地址;

    length: 和mmap()第二个参数相同;

    返回值: 函数调用成功 返回0 ,失败返回 -1;

    1.2 进程间通信

    操作内存映射区和操作管道是不一样的,得到内存映射区之后直接对内存地址进行操作 ,管道是通过文件描述符读写队列中的数据,管道的读写是阻塞的,内存映射区的读写是非阻塞的 。内存映射区创建成功之后,得到映射区的起始地址,使用相关的内存操作函数读写数据即可;

    1.2.1 有血缘关系

    由于创建子进程会将虚拟地址空间复制,那么在父进程中创建的内存映射区也会被复制到子进程中,在子进程里面就可以直接使用这块内存映射区,即对有血缘关系的进程,进行进程间通信相对简单;

    /*
    1. 先创建一个内存映射区,获得一个起始地址,使用ptr指针保存这个地址
    2. 通过fork()函数创建子进程 ->子进程中有一个内存映射区,子进程中也有一个ptr指针指向该地址
    3. 父进程向自己内存映射区写数据,数据同步到磁盘文件中,磁盘文件又同步到子进程的映射区,子  进程从自己的映射区往外读数据, 这个数据就是父进程写的
    
    */
    
    #include <sys/mman.h>
    #include <fcntl.h>
    
    int main()
    {
        // 1. 打开一个磁盘文件
        int fd = open("./english.txt", O_RDWR);
        // 2. 创建内存映射区
        void* ptr = mmap(NULL, 4000, PROT_READ|PROT_WRITE,
                         MAP_SHARED, fd, 0);
        if(ptr == MAP_FAILED)
        {
            perror("mmap");
            exit(0);
        }
    
        // 3. 创建子进程
        pid_t pid = fork();
        if(pid > 0)
        {
            // 父进程, 写数据
            const char* pt = "我是你爹, 你是我儿子吗???";
            memcpy(ptr, pt, strlen(pt)+1);
        }
        else if(pid == 0)
        {
            // 子进程, 读数据
            usleep(1);	// 内存映射区不阻塞, 为了让子进程读出数据
            printf("从映射区读出的数据: %s\n", (char*)ptr);
        }
    
        // 释放内存映射区
        munmap(ptr, 4000);
    
        return 0;
    }
    
    

    1.2.2 没有血缘关系

    没有血缘关系的进程间通信,需要在每个进程中分别创建内存映射区,但是这些进程的内存映射区必须关联相同的磁盘文件才能实现进程间的数据同步。

    A进程代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    
    int main()
    {
        // 1. 打开一个磁盘文件
        int fd = open("./english.txt", O_RDWR);
        // 2. 创建内存映射区
        void* ptr = mmap(NULL, 4000, PROT_READ|PROT_WRITE,
                         MAP_SHARED, fd, 0);
        if(ptr == MAP_FAILED)
        {
            perror("mmap");
            exit(0);
        }
        
        const char* pt = "==================我是你爹, 你是我儿子吗???****************";
        memcpy(ptr, pt, strlen(pt)+1);
    
        // 释放内存映射区
        munmap(ptr, 4000);
    
        return 0;
    }
    

    B进程代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    
    int main()
    {
        // 1. 打开一个磁盘文件
        int fd = open("./english.txt", O_RDWR);
        // 2. 创建内存映射区
        void* ptr = mmap(NULL, 4000, PROT_READ|PROT_WRITE,
                         MAP_SHARED, fd, 0);
        if(ptr == MAP_FAILED)
        {
            perror("mmap");
            exit(0);
        }
    
        // 读内存映射区
        printf("从映射区读出的数据: %s\n", (char*)ptr);
    
        // 释放内存映射区
        munmap(ptr, 4000);
    
        return 0;
    }
    

    1.3 拷贝文件

    使用内存映射区除了可以实现进程间通信,同样可以实现文件的拷贝,使用该方式拷贝文件可以减少程序员的工作量,我们只需要负责创建内存映射区和打开的磁盘文件;

    使用内存映射区拷贝文件思路:

    1. 打开被拷贝文件,得到文件描述符fd1 ,并计算出这个文件的大小 size;
    2. 创建内存映射区A并且和被拷贝文件关联,和fd1关联,得到映射区地址ptrA;
    3. 创建新文件,得到文件描述符fd2,用于存储被拷贝的数据,并将该文件大小拓展为size;
    4. 创建内存映射区B并且和新创建的文件关联,及和fd2关联起来,得到映射区地址ptrB;
    5. 进程地址空间之间的数据拷贝,memcpy(ptrB,ptrA,size) ,数据自动同步到新建文件中;
    6. 关闭内存映射区;

    文件拷贝代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    
    int main()
    {
        // 1. 打开一个操盘文件english.txt得到文件描述符
        int fd = open("./english.txt", O_RDWR);
        // 计算文件大小
        int size = lseek(fd, 0, SEEK_END);
    
        // 2. 创建内存映射区和english.txt进行关联, 得到映射区起始地址
        void* ptrA = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if(ptrA == MAP_FAILED)
        {
            perror("mmap");
            exit(0);
        }
    
        // 3. 创建一个新文件, 存储拷贝的数据
        int fd1 = open("./copy.txt", O_RDWR|O_CREAT, 0664);
        // 拓展这个新文件
        ftruncate(fd1, size);
    
        // 4. 创建一个映射区和新文件进行关联, 得到映射区的起始地址second
        void* ptrB = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
        if(ptrB == MAP_FAILED)
        {
            perror("mmap----");
            exit(0);
        }
        // 5. 使用memcpy拷贝映射区数据
        // 这两个指针指向两块内存, 都是内存映射区
        // 指针指向有效的内存, 拷贝的是内存中的数据
        memcpy(ptrB, ptrA, size);
    
        // 6. 释放内存映射区
        munmap(ptrA, size);
        munmap(ptrB, size);
        close(fd);
        close(fd1);
    
        return 0;
    }
    

    2.共享内存

    共享内存不同于内存映射区,它不属于任何进程,不受进程生命周期的影响; 通过调用Linux系统提供的系统函数就可以得到这块共享内存,使用之前让进程和共享内存进行关联,得到共享内存的起始地址之后就可以直接进行读写操作了。同样进程也可以和这块共享内存解除关联,解除关联之后就不能操作这块共享内存了。在所有进程间通信的方式中共享内存的效率是最高的

    共享内存默认不阻塞,当多个进程同时读写共享内存,可能会导致数据混乱;共享内存需要借助其他机制保证进程间的数据同步(信号量)

    2.1 创建/打开共享内存

    2.1.1 shmget 函数

    如果共享内存不存在就需要先创建出来,如果已经存在了就需要先打开该共享内存; 打开/创建共享内存的函数原型:

    #include <sys/ipc.h>
    #Include <sys/shm.h>
    int shmget(key_t key , size_t size , int shmflg);
    

    参数:

    • key: key_t整形数,通过key可以创建或打开一块共享内存,该参数的值一定要大于0;

    • size: 创建共享内存的时候,指定共享内存的大小;当打开一块存在的共享内存,size没有意义;

    • shmflg: 创建共享内存的时候指定的属性;

    1. IPC_CREAT: 创建新的共享内存,如果创建共享内存,需要指定对共享内存的操作权限(例:IPC_CREAT|0664);
    2. IPC_EXCL: 检测共享内存是否已经存在了,必须和IPC_CREAT 一起使用;

    返回值: 共享内存创建或打开成功返回标识共享内存的唯一的ID ,失败返回 -1;

    函数使用案例:

    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    //创建一个大小为4k的共享内存
    shmget(100 , 4096 ,IPC_CREAT|0644);
    
    //创建一个大小为4k的共享内存,并且检测是否存在
    //如果共享内存已经存在,创建失败,返回-1 
    shmget(100,4096,IPC_CREAT|0644|IPC_EXCL);
    
    //打开一块已经存在的共享内存
    // 函数参数虽然指定了大小和IPC_CREAT, 但是都不起作用, 因为共享内存已经存在, 只能打开, 参数4096也没有意义
    shmget(100, 4096, IPC_CREAT|0664);
    shmget(100, 0, 0);
    
    //打开一块共享内存 ,如果不存在就新建
    shmget(100,4096,IPC_CREAT|0644);
    

    2.1.2 ftok 函数

    shmget()函数的第一个参数是一个大于0的正整数 ,如果不想自己指定可以通过ftok()函数直接生成key值

    #include <sys/types.h>
    #include <sys/ipc.h>
    
    //将两个参数作为种子,生成一个 key_t 类型的数值
    key_t ftok(const char *pathname , int proj_id);
    

    参数:

    pathname: 当前操作系统中一个存在的路径;

    proj_id: 该参数只占据 int 中一个字节 ,传参的时候要将其作为char进行操作,取值:1~255

    返回值: 函数调用成功返回一个可用于创建、打开共享内存的key值 ,调用失败返回: -1;

    #include <sys/ipc.h>
    #include <sys/types.h>
    
    //根据路径生成一个key_t
    key_t key = ftok("/home/liu",'a');
    //创建或打开共享内存
    shmget(key,4096,IPC_CREAT|0644);
    

    2.2 关联和解除关联

    2.2.1 shmat 函数

    创建/打开共享内存之后必须和共享内存进行关联这样才能得到共享内存的起始地址,通过得到的内存地址进行读写操作;

    void *shmat(int shmid , const void *shmaddr , int shmflg);
    

    参数:

    shmid: 要操作的共享内存ID,是shmget()函数返回值;

    shmaddr: 共享内存的起始地址 ,内核指定,写NULL;

    shmflg: 对共享内存操作权限

    1. SHM_RDONLY: 读权限
    2. 0:读写权限

    返回值: 关联成功,返回共享内存的起始地址 ; 失败返回 (void*)-1

    2.2.2 shmdt 函数

    进程和共享内存解除关联,如果没有该操作,进程结束后进程和共享内存的关联也会自动解除;

    int shmdt(const void *shmaddr);
    

    参数: shmat() 函数的返回值 ,共享内存的起始地址;

    返回值: 关联解除成功返回 0; 失败返回 -1;

    2.3 删除共享内存

    2.3.1 shmctl 函数

    shmctl()函数是多功能函数,可以设置、获取共享内存的状态也可以将共享内存标记为删除状态。当共享内存被标记为删除状态,并不会马上被删除,知道所有进程全部和共享内存解除关联后,共享内存才会被删除。 通过shmtcl()函数只是标记删除的共享内存,在程序中多次调用时没用的;

    //共享内存控制函数
    int shmctl (int shmid , int cmd , struct shmid_ds *buf);
    
    //参数 struct shmid_ds 结构体原型
    struct shmid_ds {
    	struct ipc_perm shm_perm;    /* Ownership and permissions */
    	size_t          shm_segsz;   /* Size of segment (bytes) */
    	time_t          shm_atime;   /* Last attach time */
    	time_t          shm_dtime;   /* Last detach time */
    	time_t          shm_ctime;   /* Last change time */
    	pid_t           shm_cpid;    /* PID of creator */
    	pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
        // 引用计数, 多少个进程和共享内存进行了关联
    	shmatt_t        shm_nattch;  /* 记录了有多少个进程和当前共享内存进行了管联 */
    	...
    };
    

    参数:

    • shmid: 要操作的共享内存ID,shmget()函数的返回值;

    • cmd: 下一步要做的操作

    1. IPC_STAT: 得到当前共享内存的状态;
    2. IPC_SET: 设置当前共享内存的状态;
    3. IPC_RMID: 标记共享内存要被删除;

    buf:

    1. cmd == IPC_STAT ,作为传出参数,会得到共享内存的相关属性;
    2. cmd == IPC_SET ,作为传入参数,将用户的自定义属性设置到共享内存中;

    返回值: 函数调用成功 返回 大于等于 0 ; 调用失败返回 -1;

    2.3.2 相关shell命令

    • 使用 ipcs 添加参数 -m 可以查看系统中共享内存的详细信息;
    liu@liu-Ubuntu:~$ ipcs -m
    
    ------------ 共享内存段 --------------
    键        shmid      拥有者  权限     字节     连接数  状态      
    0x00000000 6          liu        600        16777216   2          目标       
    0x00000000 9          liu        600        134217728  2          目标       
    0x00000000 12         liu        600        524288     2          目标       
    0x00000000 13         liu        600        524288     2          目标       
    0x00000000 14         liu        600        524288     2          目标       
    0x00000000 17         liu        600        524288     2          目标       
    0x00000000 18         liu        600        524288     2          目标       
    0x00000000 19         liu        600        19488      2          目标       
    0x00000000 21         liu        600        68400      2          目标 
    

    使用 ipcrm 命令可以标记删除某块共享内存

    # key == shmget的第一个参数
    $ ipcrm -M shmkey  
    
    # id == shmget的返回值
    $ ipcrm -m shmid	
    

    2.3.3 共享内存状态

    // 参数 struct shmid_ds 结构体原型          
    struct shmid_ds {
    	struct ipc_perm shm_perm;    /* Ownership and permissions */
    	size_t          shm_segsz;   /* Size of segment (bytes) */
    	time_t          shm_atime;   /* Last attach time */
    	time_t          shm_dtime;   /* Last detach time */
    	time_t          shm_ctime;   /* Last change time */
    	pid_t           shm_cpid;    /* PID of creator */
    	pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
        // 引用计数, 多少个进程和共享内存进行了关联
    	shmatt_t        shm_nattch;  /* 记录了有多少个进程和当前共享内存进行了管联 */
    	...
    };
    

    共享内存的信息存储在 struct shmid_ds 的结构体中,其中有一个非常重要的成员 shm_nattch ,该成员变量记录着当前共享内存关联的进程个数(引用计数)当共享内存被标记为删除状态,并且引用计数为0之后共享内存才会被删除。

    当共享内存被标记为删除状态之后,共享内存的状态也会发生变化,共享内存内部维护的 key 从一个正整数变为 0,其属性从公共的变为私有的。这里的私有是指只有已经关联成功的进程才允许继续访问共享内存,不再允许新的进程和这块共享内存进行关联了。 下图演示了共享内存的状态变化:

    在这里插入图片描述

    2.4 进程间通信

    使用共享内存实现进程间通信的流程:

    /*
    1. 调用Linux系统API创建一块共享内存
            ---此块内存不属于任何进程 , 默认 进程不能对其进行操作;
            
    2. 准备好 进程A 、进程B,两个进程需要和创建的共享内存进行关联
          --- 关联操作: 调用Linux系统API
          --- 关联成功之后 ,得到这块共享内存的起始地址
          
    3. 在进程A  或 进程B中对共享内存进行读写操作
         --- 读内存: printf() 等
         --- 写内存: memcpy() 等
         
    4. 通信完成,让进程A\B和共享内存解除关联
         --- 解除成功 ,进程A、B不能再操作共享内存
         --- 共享内存不受进程生命周期的影响
         
    5. 共享内存不在使用后,将其删除
         --- 调用Linux系统API,删除后,该内存被内核回收
    */
    

    写进程内存代码:

    //写进程
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/fcntl.h>
    #include<sys/ipc.h>
    #include <sys/shm.h>
    
    int main()
    {
        //1. 创建共享内存 ,大小4k
        int shmid = shmget(100,4096,IPC_CREAT|0664);
        if (shmid ==-1)
        {
            perror("shmget error");
            return -1;
        }
    
        //2. 当前进程和共享进程关联
        void *ptr = shmat(shmid,NULL,0);
        if (ptr == (void*) -1)
        {
            perror("shmat error");
            return -1;
        }
    
        //3. 写共享内存
        const char *p = "共享内存效率高";
        memcpy(ptr ,p ,strlen(p)+1);
    
        //阻塞程序
        printf("按任意键继续,删除共享内存\n");
        getchar();
        // shmdt(ptr);
    
        // //删除共享内存
        // shmctl(shmid,IPC_RMID,NULL);
        printf("共享内存已经被删除\n");
    
        return 0;
    }
    

    读进程代码

    //读进程
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/fcntl.h>
    #include<sys/ipc.h>
    #include <sys/shm.h>
    
    
    int main()
    {
        //1. 创建(打开)共享内存
        int shmid = shmget(100,0,0);
        if(shmid ==-1)
        {
            perror("shmget error");
            return -1;
        }
    
        //2. 当前进程和共享内存关联
        void *ptr =shmat(shmid,NULL,0);
        if (ptr ==(void *)-1)
        {
            perror("shmat error");
            return -1;
        }
    
        //3. 读共享内存
        printf("共享内存中数据 : %s \n",(char*)ptr);
    
        //阻塞程序
        printf("按任意键继续 ,删除共享内存\n");
        getchar();
    
        shmdt(shmid);
    
        //删除共享内存
        shmctl(shmid,IPC_RMID,NULL);
        printf("共享内存已经被删除\n");
         return 0;
    }
    

    2.5 shm 和mmap区别

    共享内存内存映射区 都可以实现进程间通信 ,其两者是有区别的:

    • 实现进程间通信的方式:
    1. shm: 多个进程只需要一块共享内存,共享内存不属于进程,需要和进程关联才能使用;
    2. 内存映射区: 位于每个进程的虚拟地址空间中,且需要关联一个磁盘文件才能实现进程间数据通信;
    • 效率:
    1. shm: 直接对内存操作,效率高;
    2. 内存映射区: 需要内存和文件之间的数据同步 ,效率低;
    • 生命周期:
    1. shm: 进程退出对共享内存没有影响 , 调用相关函数/命令/关机 才能删除共享内存
    2. 内存映射区: 进程退出,内存映射区没了
    • 数据完整性(突然断电)
    1. shm: 数据直接存储在物理内存上 ,断电后系统关闭,内存数据丢失;
    2. 内存映射区: 可以完整的保存数据 ,内存映射区数据会同步到磁盘文件;
    展开全文
  • 文章目录 方案1 == free命令 方案2 == /proc/meminfo文件 free内存不够,则从buffer、cache中取 内存概念 total:总内存,物理内存总数 used:已经使用的内存数 free:空闲的内存数 shared:多个进程共享内存数 ...
  • linux 删除 共享内存 how to list and delete shared memory in linux? 如何在Linux中列出和删除共享内存? List all shared memories in your Linux Systems > $ ipcs -m 列出您的Linux 系统中的所有共享...
  • 里面是两个实验,一个共享内存方式的进程间通信,另一个是shell命令解释器。两个都是linux版本的。
  • adb shell toptop命令提供了实时的对系统处理器的...内存使用和执行时间对任务进行排序.top 用法>adb shell top -hUsage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [-t ] [ -h...
  • 进程间通信(IPC): 进程间通信(IPC)是操作系统为用户提供...数据共享(共享内存);进程控制(信号量); 从unix而来的管道;systemV标准的共享内存、消息队列和信号量。 管道: 本质:内核中的一块缓冲区;多个进
  • 进程间通信 管道 匿名管道 命名管道 pipe mkfifo 共享内存 ftok shmget shmat shmdt shmctl system v IPC
  • 4)利用Linux的共享内存通信机制实现两个进程间的通信 编写程序sender,它创建一个共享内存,然后等待用户通过终端输入一串字符,并将这串字符通过共享内存发送给receiver;最后,它等待receiver的应答,收到应答...
  • 一、方法 代码如下:/** * 执行一个shell命令,并返回字符串值 * * @param cmd * 命令名称&参数组成的数组(例如:{“/system/bin/cat”, “/proc/version”}) * @param workdirectory * 命令执行路径...
  • Shell编程.pdf

    2022-01-14 11:43:07
    已经装有Linux系统
  • adb shell 内存参数详解

    千次阅读 2018-02-02 11:08:31
    摘自https://www.cnblogs.com/zl1991/p/6644998.html,感谢原创作者!!! 1、adb shell procrank  PID Vss Rss Pss Uss cmdline 32657 2254196K 372752K 238947K 217
  • linux--shell脚本记录进程内存变化VmRSS|VmSize(内存泄漏)1 介绍2 虚拟内存(Virtual Memory)与驻留内存(Resident Memory)3 VmRSS与VmSize4 如下每10分钟统计一次参考 1 介绍 记录进程的内存增长情况,定位是否...
  • Linux共享内存及函数详解(含示例)

    千次阅读 2020-12-03 14:53:32
    共享内存的概念 共享内存是指多个进程可以把一段内存共同的内存映射到自己的进程空间中,从而实现数据的共享和传输,它是存在与内核级别的一种资源,是所有进程间通信中方式最快的一种。 在shell环境下可以使用ipcs...
  • 管道 消息队列 共享内存的优缺点

    千次阅读 2017-08-23 16:56:20
    无法严格保证提供对共享内存块的独占访问,甚至是在您通过使用IPC_PRIVATE创建新的共享内存块的时候也不能保证访问的独占性。 同时,多个使用共享内存块的进程之间必须协调使用同一个键值。    ...
  • linux内存共享源代码

    2014-03-27 21:52:43
    在Linux利用内存共享实现两个shell窗口的通信
  • 利用共享内存实现多进程交互

    千次阅读 2018-02-27 15:41:55
    一、什么是共享内存? 共享内存(shared memory)是Unix下的多进程之间的通信方法,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。共享内存指在多处理器的计算机系统中...
  • Linux共享内存之段错误

    千次阅读 2017-06-08 21:15:09
    最近为了学习操作系统,练习写一个shell,然后其中采用了共享内存的方案。 然而在共享内存初始化的时候移植了之前写共享内存实验已经成功的初始化代码,却出现了段错误。主要代码如下: #include "...
  • linux 共享内存 查看和删除

    千次阅读 2020-01-27 14:45:07
    您可以使用shell命令来查看与释放已经分配的共享内存,下面将详细说明如何进行查看和释放分配的共享内存的方法。 预备知识 Linux中通过API函数shmget创建的共享内存一般都是在程序中使用shmctl来释放的,但是有时...
  • //查看共享内存 [app_usr@js2test01 shell]$ ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x0122f9df 12419074 app_usr 666 70604918 0 0x0001b3ef 14450...
  • 通过共享内存进行进程间通信

    千次阅读 2013-08-25 00:20:13
    UNIX 系统同时运行大量应用程序,有限的物理资源要在它们之间共享。处理器能力被划分为时间片,应用程序映像经常被换入和换出真实内存,设备访问由需求驱动,还受到访问权限的限制。尽管您的 shell 提示符不断闪烁,...
  • Native Heap:Native代码分配的内存,虚拟机和Android框架分配内存。关于什么是Native代码,即非Java代码分配的内存。详细介绍请找百度。 Dalvik Heap:Java对象分配的占据内存 Dalvik Other:类数据结构和索引占...
  • Shell脚本实现ftok函数

    2021-01-11 01:01:05
    三种 IPC 对象是共享内存,信号灯和消息。”当使用到 IPC 的这些对象时,你需要为每个对象创建一个 Key。虽然理论上来说我们在定义一个 IPC Key 的时候可以使用任意自己喜欢的 Key ,但为了避免与其他的程序产生定义...
  • Android 匿名共享内存demo篇(一)

    千次阅读 2019-03-01 11:18:49
    Android系统的IPC方式通常为:文件、socket、binder、messenger、AIDL、ContentProvider,此外还有个Anonymous Shared Memory(匿名共享内存),这篇文章介绍Ashm基础使用相关知识。 Android api27加入了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 97,681
精华内容 39,072
关键字:

shell 共享内存