ref:https://blog.csdn.net/qq_35733751/article/details/82872197
多线程共享进程的地址空间,如果多个线程需要访问同一块内存,用全局变量即可。
在多进程中,每个进程的地址空间是独立的,不共享的,如果多个进程需要访问同一块内存,不能用全局变量,只能用共享内存。
共享内存Shared Memory 允许多个进程(不要求进程之间有血缘关系)访问同一块内存空间,是多个进程之间共享和传递数据最高效的方式。进程可以将共享内存连接到他们自己的地址空间,如果某个进程修改了共享内存中的数据,其他的进程读到的数据也会改变。
共享内存没有提供锁机制,也就是说,在某一个进程对共享内存进行读/写的时候,不会阻止其它进程对它的读/写。如果要对共享内存的读/写加锁,可以使用信号量。
Linux 操作共享内存需要四步:
- 调用shmget函数获取或创建共享内存
- 调用shmat函数把共享内存连接到当前进程的地址空间
- 调用shmdt函数把共享内存从当前进程中分离 shmdt是用来取消进程空间的地址空间和共享内存的物理地址的挂接,不让进程访问共享内存了。
- 调用shmctl函数删除共享内存
通常不需要第4个,除非整个服务停止了。
查看当前的共享内存命令
ipcs -m
(base) ubuntu@ubuntu:~$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 360454 ubuntu 600 1048576 2 dest
0x00000000 229384 ubuntu 700 131072 2 dest
0x00000000 229385 ubuntu 700 1290240 2 dest
0x00000000 360459 ubuntu 600 524288 2 dest
0x00000000 229389 ubuntu 600 524288 2 dest
0x00000000 229393 ubuntu 600 4194304 2 dest
0x00000000 327698 ubuntu 700 8192 2 dest
0x00000000 21 ubuntu 600 57024 2 dest
0x00000000 24 ubuntu 600 524288 2 dest
0x00000000 29 ubuntu 600 4194304 2 dest
0x00000000 327713 ubuntu 700 2101248 2 dest
0x00000000 36 ubuntu 777 3110400 2 dest
0x00000000 37 ubuntu 777 3110400 2 dest
0x00000000 196647 ubuntu 700 16384 2 dest
0x00000000 40 ubuntu 600 806400 2 dest
0x00000000 41 ubuntu 600 7904376 2 dest
0x00000000 196650 ubuntu 700 20480 2 dest
0x5106002b 44 ubuntu 600 1 1
0x00000000 45 ubuntu 600 986168 2 dest
0x00000000 47 ubuntu 600 7574616 2 dest
0x00000000 48 ubuntu 600 914292 2 dest
0x00000000 196663 ubuntu 700 2242800 2 dest
0x00000000 196669 ubuntu 700 1474560 2 dest
参数解析:
key 是 共享内存的标识符, 16进制,owner 创建共享内存的用户或进程的用户ID。perms 权限 bytes 内存的大小 nattch 链接进来的进程数量 status 状态
第七列是共享内存的状态status。其中显示“dest”表示共享内存段已经被删除,但是还有用户在使用它,当该段内存的mode字段设置为 SHM_DEST时就会显示“dest”。当用户调用shmctl的IPC_RMID时,内存先查看多少个进程与这个内存关联着,如果关联数为0,就会销 毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,如果所有进程都不用则删除这段共享内存。
ipcrm -m shmid 删除共享内存
以上列出的是使用默认的"ipcs -m"命令输出的列。
//
// Created by ubuntu on 9/7/23.
//
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
struct st_pid {
int pid; // 进程编号
char names[51]; // 进程名称
};
int main(int argc, char *argv[]) {
int key = 0x1234;
int shmid;
// 调用shmget函数获取或创建共享内存
if ((shmid = shmget(key, sizeof(struct st_pid), 0640 | IPC_CREAT)) == -1) {
printf("shmget(Ox1234) failed \n");
return -1;
}
struct st_pid *stpid = 0;
// 调用shmat函数把共享内存连接到当前进程的地址空间,On success, shmat() returns the address of the attached shared memory segment
if((stpid = (struct st_pid *)shmat(shmid, stpid, 0)) == (void *) -1) {
printf("shmat failed\n");
return -1;
}
//把共享内存从当前进程中分离
//shmdt(stpid);
}
要注意的是这一部分:
struct st_pid *)shmat(shmid, stpid, 0))
man 啥看shmat, 它返回的是void × 类型,所以要强制转换何曾 struct st_pid * , 因为是要用st_pid * 做的数据接收。
同时手册明确说了,错误后是返回值是 void× 类型的 -1
SYNOPSIS
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
RETURN VALUE
On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and
errno is set to indicate the cause of the error.
On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the error.
第三个参数:int shmflg 暂时用不到,需要传0;
shmflg参数:是一个权限标志位,如果shmflg = 0表示默认权限可读写,如果指定shmflg = HM_RDONLY表示只读模式,其他为读写模式。
参数shmaddr:表示进程空间的虚拟地址,shmat函数会把shmaddr地址映射到共享内存,具体如何映射是由参数shmaddr和shmflg来决定。
ref:ttps://blog.csdn.net/qq_35733751/article/details/82872197
删除共享内存:
函数原型:
shmctl(shmid, IPC_RMID, 0)
IPC_RMID表示没有进程绑定的时候才删除,第三个参数是啥意思???
IPC_RMID Mark the segment to be destroyed. The segment will actually be destroyed only after the last process de‐
taches it (i.e., when the shm_nattch member of the associated structure shmid_ds is zero). The caller must
be the owner or creator of the segment, or be privileged. The buf argument is ignored.
If a segment has been marked for destruction, then the (nonstandard) SHM_DEST flag of the shm_perm.mode
field in the associated data structure retrieved by IPC_STAT will be set.
The caller must ensure that a segment is eventually destroyed; otherwise its pages that were faulted in
will remain in memory or swap.
See also the description of /proc/sys/kernel/shm_rmid_forced in proc(5).
(base) ubuntu@ubuntu:~/muke01/01sharemem$ ipcs -m | grep 1234
0x00001234 1015831 ubuntu 640 56 1
attach 是1了,代表有一个process attach了共享内存的地址。
//
// Created by ubuntu on 9/7/23.
//
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
struct st_pid {
int pid; // 进程编号
char names[51]; // 进程名称
};
int main(int argc, char *argv[]) {
int key = 0x1234;
int shmid;
// 调用shmget函数获取或创建共享内存
if ((shmid = shmget(key, sizeof(struct st_pid), 0640 | IPC_CREAT)) == -1) {
printf("shmget(Ox1234) failed \n");
return -1;
}
struct st_pid *stpid = 0;
// 调用shmat函数把共享内存连接到当前进程的地址空间,On success, shmat() returns the address of the attached shared memory segment
if ((stpid = (struct st_pid *) shmat(shmid, stpid, 0)) == (void *) -1) {
printf("shmat failed\n");
return -1;
}
printf("pid=%d,name=%s\n", stpid->pid, stpid->names);
stpid->pid = getpid();
strcpy(stpid->names, argv[1]);
printf("pid=%d,name=%s\n", stpid->pid, stpid->names);
sleep(10);
//把共享内存从当前进程中分离
shmdt(stpid);
// 删除共享内存
// if (shmctl(shmid, IPC_RMID, 0) == -1) {
// printf("shmctl failed \n");
// return -1;
// }
}