Ⅰ 如何设置linux的共享内存
我们可以修改shmmax内核参数,使SGA存在于一个共享内存段中。
通过修改/proc/sys/kernel/shmmax参数可以达到此目的。
[root@neirong root]# echo 1073741824 > /proc/sys/kernel/shmmax
[root@neirong root]# more /proc/sys/kernel/shmmax
1073741824这里设为1G。
对于shmmax文件的修改,系统重新启动后会复位。可以通过修改 /etc/sysctl.conf 使更改永久化。
在该文件内添加以下一行 kernel.shmmax = 1073741824 这个更改在系统重新启动后生效.
1、设置 SHMMAX
SHMMAX
参数定义共享内存段的最大尺寸(以字节为单位)。在设置 SHMMAX 时,切记 SGA 的大小应该适合于一个共享内存段。 SHMMAX 设置不足可能会导致以下问题:
ORA-27123:unable to attach to shared memory segment
您可以通过执行以下命令来确定 SHMMAX 的值:
# cat /proc/sys/kernel/shmmax
33554432
SHMMAX 的默认值是 32MB 。我一般使用下列方法之一种将 SHMMAX 参数设为 2GB :
通过直接更改 /proc 文件系统,你不需重新启动机器就可以改变 SHMMAX 的默认设置。我使用的方法是将以下命令放入 /etc/rc.local 启动文件中:
# >echo "2147483648" > /proc/sys/kernel/shmmax
您还可以使用 sysctl 命令来更改 SHMMAX 的值:
# sysctl -w kernel.shmmax=2147483648
最后,通过将该内核参数插入到 /etc/sysctl.conf 启动文件中,您可以使这种更改永久有效:
# echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf
2、设置 SHMMNI
我们现在来看 SHMMNI 参数。这个内核参数用于设置系统范围内共享内存段的最大数量。该参数的默认值是 4096 。这一数值已经足够,通常不需要更改。
您可以通过执行以下命令来确定 SHMMNI 的值:
# cat /proc/sys/kernel/shmmni
4096
3、设置 SHMALL
最后,我们来看 SHMALL 共享内存内核参数。该参数控制着系统一次可以使用的共享内存总量(以页为单位)。简言之,该参数的值始终应该至少为:
ceil(SHMMAX/PAGE_SIZE)
SHMALL 的默认大小为 2097152 ,可以使用以下命令进行查询:
# cat /proc/sys/kernel/shmall
2097152
SHMALL 的默认设置对于我们的 Oracle9 i RAC 安装来说应该足够使用。
注意: 在 i386 平台上 Red Hat Linux 的 页面大小 为 4096 字节。但是,您可以使用 bigpages ,它支持配置更大的内存页面尺寸。
Ⅱ linux 共享内存 可不可以不加锁呢 系统有两个进程,一个负责写入,一个负责读取
Linux共享内存可以不用加锁,不过需要一种机制来标记共享内存的读写状态;
也就是说要让两个进程知道:
1)负责写入的进程,必须知道当前共享内存是否可以写入,上一次的写入内容是否有被负责读取的进程读走;
2)负责读取的进程,必须知道当前共享内存是否需要读取,防止重复读取。
一般的这种标记机制是通过以下方式来简单实现:
1)通过读写锁来控制;
2)共享内存上设置一个地方,专门存放当前共享内存的读写状态;
Ⅲ Linux进程间通信(互斥锁、条件变量、读写锁、文件锁、信号灯)
为了能够有效的控制多个进程之间的沟通过程,保证沟通过程的有序和和谐,OS必须提供一定的同步机制保证进程之间不会自说自话而是有效的协同工作。比如在 共享内存的通信方式中,两个或者多个进程都要对共享的内存进行数据写入,那么怎么才能保证一个进程在写入的过程中不被其它的进程打断,保证数据的完整性 呢?又怎么保证读取进程在读取数据的过程中数据不会变动,保证读取出的数据是完整有效的呢?
常用的同步方式有: 互斥锁、条件变量、读写锁、记录锁(文件锁)和信号灯.
互斥锁:
顾名思义,锁是用来锁住某种东西的,锁住之后只有有钥匙的人才能对锁住的东西拥有控制权(把锁砸了,把东西偷走的小偷不在我们的讨论范围了)。所谓互斥, 从字面上理解就是互相排斥。因此互斥锁从字面上理解就是一点进程拥有了这个锁,它将排斥其它所有的进程访问被锁住的东西,其它的进程如果需要锁就只能等待,等待拥有锁的进程把锁打开后才能继续运行。 在实现中,锁并不是与某个具体的变量进行关联,它本身是一个独立的对象。进(线)程在有需要的时候获得此对象,用完不需要时就释放掉。
互斥锁的主要特点是互斥锁的释放必须由上锁的进(线)程释放,如果拥有锁的进(线)程不释放,那么其它的进(线)程永远也没有机会获得所需要的互斥锁。
互斥锁主要用于线程之间的同步。
条件变量:
上文中提到,对于互斥锁而言,如果拥有锁的进(线)程不释放锁,其它进(线)程永远没机会获得锁,也就永远没有机会继续执行后续的逻辑。在实际环境下,一 个线程A需要改变一个共享变量X的值,为了保证在修改的过程中X不会被其它的线程修改,线程A必须首先获得对X的锁。现在假如A已经获得锁了,由于业务逻 辑的需要,只有当X的值小于0时,线程A才能执行后续的逻辑,于是线程A必须把互斥锁释放掉,然后继续“忙等”。如下面的伪代码所示:
1.// get x lock
2.while(x
Ⅳ 探讨一下 Linux 共享内存的 N 种方式
关于 Linux 共享内存,写得最好的应该是宋宝华的 《世上最好的共享内存》 一文。
本文可以说是对这篇文章的学习笔记,顺手练习了一下 rust libc —— shichaoyuan/learn_rust/linux-shmipc-demo
按照宋宝华的总结,当前有四种主流的共享内存方式:
前两种方式比较符合传统的用法,共享内存做为进程间通信的媒介。
第三种方式更像是通过传递内存“句柄”进行数据传输。
第四种方式是为设备间传递数据设计,避免内存拷贝,直接传递内存“句柄”。
这里尝试了一下第二种和第三种方式。
这套 API 应该是最普遍的 —— shm_open + mmap,本质上来说 Aeron 也是用的这种方式(关于 Aeron 可以参考 我之前的文章 )。
看一下 glibc 中 shm_open 函数的实现就一清二楚了:
shm_open 函数就是在 /dev/shm 目录下建文件,该目录挂载为 tmpfs,至于 tmpfs 可以简单理解为存储介质是内存的一种文件系统,更准确的理解可以参考官方文档 tmpfs.txt 。
然后通过 mmap 函数将 tmpfs 文件映射到用户空间就可以随意操作了。
优点:
这种方式最大的优势在于共享的内存是有“实体”(也就是 tmpfs 中的文件)的,所以多个进程可以很容易通过文件名这个信息构建共享内存结构,特别适合把共享内存做为通信媒介的场景(例如 Aeron )。
缺点:
如果非要找一个缺点的话,可能是,文件本身独立于进程的生命周期,在使用完毕后需要注意删除文件(仅仅 close 是不行的),否则会一直占用内存资源。
memfd_create 函数的作用是创建一个匿名的文件,返回对应的 fd,这个文件当然不普通,它存活在内存中。更准确的理解可以参考官方文档 memfd_create(2) 。
直观理解,memfd_create 与 shm_open 的作用是一样的,都是创建共享内存实体,只是 memfd_create 创建的实体是匿名的,这就带了一个问题:如何让其它进程获取到匿名的实体?shm_open 方式有具体的文件名,所以可以通过打开文件的方式获取,那么对于匿名的文件怎么处理呢?
答案是:通过 Unix Domain Socket 传递 fd。
rust 的 UDS 实现:
rust 在 std 中已经提供了 UDS 的实现,但是关于传递 fd 的 send_vectored_with_ancillary 函数还属于 nightly-only experimental API 阶段。所以这里使用了一个三方 crate —— sendfd ,坦白说可以自己实现一下,使用 libc 构建好 SCM_RIGHTS 数据,sendmsg 出去即可,不过细节还是挺多,我这里就放弃了。
这套 API 设计更灵活,直接拓展了我的思路,本来还是受限于 Aeron 的用法,如果在这套 API 的加持下,是否可以通过传递数据包内存块(fd)真正实现零拷贝呢?
优点:
灵活。
缺点:
无
Ⅳ linux两种共享内存的区别
持久性不同、文件反射方式不同。
1、持久性不同。sysvshm是持久化的,除非被一个进程明确的删除,否则它始终存在于内存里,直到系统关机。mmap映射的内存在不是持久化的,假如进程关闭,映射随即失效,除非事前已经映射到了一个文件上。
2、文件反射方式不同。前者用COW的方式,把文件映射到当前的进程空间,修改操作不会改动源文件。后者直接把文件映射到当前的进程空间,所有的修改会直接反应到文件的page cache,而后由内核自动同步到映射文件上。
Ⅵ linux共享锁与排斥锁的作用
共享锁【S锁】又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。排他锁【X锁】又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
Ⅶ linux查看共享内存命令
共享内存查看
使用ipcs命令,不加如何参数时,会把共享内存、信号量、消息队列的信息都打印出来,如果只想显示共享内存信息,使用如下命令:
[root@localhost ~]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 1867776 root 600 393216 2 dest
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,如果所有进程都不用则删除这段共享内存。
Ⅷ Linux进程通信实验(共享内存通信,接上篇)
这一篇记录一下共享内存实验,需要linux的共享内存机制有一定的了解,同时也需要了解POSIX信号量来实现进程间的同步。可以参考以下两篇博客: https://blog.csdn.net/sicofield/article/details/10897091
https://blog.csdn.net/ljianhui/article/details/10253345
实验要求:编写sender和receiver程序,sender创建一个共享内存并等待用户输入,然后把输入通过共享内存发送给receiver并等待,receiver收到后把消息显示在屏幕上并用同样方式向sender发送一个over,然后两个程序结束运行。
这个实验的难点主要在于共享内存的创建和撤销(涉及到的步骤比较多,需要理解各步骤的功能),以及实现两个进程间的相互等待(使用信号量来实现,这里使用了有名信号量)
实验心得:学习理解了linux的共享内存机制以及POSIX信号量机制。
两个实验虽然加强了对linux一些机制的理解,但是感觉对linux的学习还不够,需要继续学习。
Ⅸ 共享内存原理
Linux的2.2.x内核支持多种共享内存方式,如mmap()系统调用,Posix共享内存,以及系统V共享内存。
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
系统V共享内存原理
进程间需要共享的数据被放在一个叫做IPC共享内存区域的地方,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。系统V共享内存通过shmget获得或创建一个IPC共享内存区域,并返回相应的标识符。内核在保证shmget获得或创建一个共享内存区,初始化该共享内存区相应的shmid_kernel结构注同时,还将在特殊文件系统shm中,创建并打开一个同名文件,并在内存中建立起该文件的相应dentry及inode结构,新打开的文件不属于任何一个进程(任何进程都可以访问该共享内存区)。所有这一切都是系统调用shmget完成的。
Linux 有一个系统调用叫 mmap(),这个 mmap() 可以把一个文件映射到进程的地址空间(进程使用的虚拟内存),这样进程就可以通过读写这个进程地址空间来读写这个文件。
你可能会觉得奇怪,我明明写的是内存啊,怎么会变成写文件了呢?他们之间是怎么转化的呢?
没错,你写的确实是内存,但是你写的这个内存不是普通的内存,你写在这个内存上的内容,过段时间后会被内核写到这个文件上面。而写文件,其实最后都会变成写数据到设备里(硬盘、Nand Flash 等)。
mmap的优点主要在为用户程序随机的访问,操作,文件提供了一个方便的操作方法;其次就是为不同进程共享大批量数据提供高效的手段;另外就是对特大文件(无法一次性读入内存)的处理提供了一种有效的方法。
内核里存在着一个特殊的文件系统,这个文件系统的存储介质不是别的,正是 RAM。
在 shmget() 调用之后,系统会为你在这个文件系统上创建一个文件,但是这个时候仅仅是创建了这个文件。
然后你就应该调用 shmat() 了,调用 shmat() 之后,内核会使用 mmap 把这个文件映射到你的进程地址空间,这个时候你就能直接读写映射后的地址了。
过段时间,内核把你写的 内容写到了文件里面,但是,这个文件的存储介质是内存,所以他会怎么做?看明白了吧?
答案:他会写入内存呀
我们先来看看如果不使用内存映射文件的处理流程是怎样的,首先我们得先读出磁盘文件的内容到内存中,然后修改,最后回写到磁盘上。第一步读磁盘文件是要经过一次系统调用的,它首先将文件内容从磁盘拷贝到内核空间的一个缓冲区,然后再将这些数据拷贝到用户空间,实际上是两次数据拷贝。第三步回写也一样也要经过两次数据拷贝。
所以我们基本上会有四次数据的拷贝了,因为大文件数据量很大,几十GB甚至更大,所以拷贝的开销是非常大的。
而内存映射文件是操作系统的提供的一种机制,可以减少这种不必要的数据拷贝,从而提高效率。它由mmap()将文件直接映射到用户空间,mmap()并没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行了一次数据拷贝 ,比read进行两次数据拷贝要好上一倍,因此,内存映射的效率要比read/write效率高。
一般来说,read write操作可以满足大多数文件操作的要求,但是对于某些特殊应用领域所需要的几十GB甚至更大的存储,这种通常的文件处理方法进行处理显然是行不通的。
mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。
当使用mmap映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用.但需注意,直接对该段内存写时不会写入超过当前文件大小的内容.
参考地址:
Ⅹ linux|进程间通信如何加锁
进程间通信有一种[共享内存]方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?
关于进程间的通信方式估计大多数人都知道,这也是常见的面试八股文之一。
个人认为这种面试题没什么意义,无非就是答几个关键词而已,更深入的可能面试官和面试者都不太了解。
关于进程间通信方式我之前在【这篇文章】中有过介绍,感兴趣的可以移步去看哈。
进程间通信有一种[共享内存]方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?
我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?
我找到了两种方法,信号量和互斥锁。
直接给大家贴代码吧,首先是信号量方式:
代码中的MEOW_DEFER,它内部的函数会在生命周期结束后触发。它的核心函数其实就是下面这四个:
具体含义大家应该看名字就知道,这里的重点就是sem_init中的pshared参数,该参数为1表示可在进程间共享,为0表示只在进程内部共享。
第二种方式是使用锁,即pthread_mutex_t,可是pthread_mutex不是用作线程间数据竞争的吗,怎么能用在进程间呢?
可以给它配置一个属性,示例代码如下:
它的默认属性是进程内私有,但是如果给它配置成PTHREAD_PROCESS_SHARED,它就可以用在进程间通信中。
相关视频推荐
360度无死角讲解进程管理,调度器的5种实现
Linux进程间通信-信号量、消息队列和共享内存
学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括 C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg 等),免费分享
完整代码如下:
我想这两种方式应该可以满足我们日常开发过程中的大多数需求。
锁的方式介绍完之后,可能很多朋友自然就会想到原子变量,这块我也搜索了一下。但是也不太确定C++标准中的atomic是否在进程间通信中有作用,不过看样子boost中的atomic是可以用在进程间通信中的。
其实在研究这个问题的过程中,还找到了一些很多解决办法,包括:
Disabling Interrupts
Lock Variables
Strict Alternation
Peterson's Solution
The TSL Instruction
Sleep and Wakeup
Semaphores
Mutexes
Monitors
Message Passing
Barriers
这里就不过多介绍啦,大家感兴趣的可以自行查阅资料哈。