🧨🧨🧨🧨🧨🧨🧨🧨🧨除夕篇🧨🧨🧨🧨🧨🧨🧨🧨🧨

🎉❤️🎉❤️🎉❤️🎉❤️🎉❤️祝各位程序员们马年大吉 万事如意!❤️🎉❤️🎉❤️🎉❤️🎉❤️🎉
目录
[2.接着System V 共享内存(1)继续讲](#2.接着System V 共享内存(1)继续讲)
1.知识回顾
参见OS52.【Linux】System V 共享内存(1)文章复习共享内存的基础知识
2.接着System V 共享内存(1)继续讲
通信代码
上篇文章的最后实现了让两个进程使用共享内存进行通信
shm1.cpp写入:
cpp
#include <stdio.h>
#include <iostream>
#include "header.hpp"
int main()
{
//为了减小代码行数,系统调用的错误执行结果都没有判断
int shmid=get_new_shared_memory();
char* start_addr=(char*)shmat(shmid,nullptr,0);
for (;;)
{
sleep(1);
std::cout<<start_addr;
fflush(stdout);
}
shmdt(start_addr);
shmctl(shmid,IPC_RMID,nullptr);
return 0;
}
shm2.cpp写入:
cpp
#include <stdio.h>
#include <iostream>
#include "header.hpp"
int main()
{
//为了减小代码行数,系统调用的错误执行结果都没有判断
int shmid=get_old_shared_memory();
char* start_addr=(char*)shmat(shmid,nullptr,0);
for (;;)
{
std::cin>>start_addr;
}
shmdt(start_addr);
return 0;
}
运行结果:

分析细节
注意到:
cpp
for (;;)
{
std::cin>>start_addr;
}
没有将输入暂存到缓冲区,然后将缓冲区数据拷贝到start_addr处
结论
结论: 1.一旦有了共享内存,可以将其挂接到进程自己的地址空间中,进程可以直接把他当成自己的内存空间来使用
2. 一旦有数据写入到共享内存,进程就能立马看到, 不需要经过系统调用
共享内存的特点
从以上结论可以得出共享内存的特点: 共享内存没有同步互斥值之类的保护机制
对比管道,管道中如果没有数据,那么进程读管道会被阻塞
其次,共享内存是所有的进程间通信中最快的,因为不需要经过系统调用
再之,共享内存内部的数据,由用户自己维护
使用管道为共享内存添加同步机制
共享内存无同步机制,可以借助管道
管道的复习:
OS43.【Linux】进程间通信 管道通信理论部分
例如: shm2.out向共享内存写入数据,shm1.out读数据,可以为共享内存配上管道来保证同步
1.读写端正常,管道为空,读端阻塞,此时不能读共享内存数据
2.读写端正常,管道不为空,读端不阻塞,此时能读共享内存数据
header.cpp写入:
cpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#define SIZE 1024
#define PROJ_ID 0x1344
key_t get_key()
{
char buffer[SIZE];
char* pathname=getcwd(buffer,sizeof(buffer));
if (pathname==nullptr)
{
perror("getcwd failed");
exit(1);
}
return ftok(pathname,PROJ_ID);
}
int get_new_shared_memory()
{
key_t key=get_key();
//申请新的共享内存
int shmid=shmget(key,4097,IPC_CREAT|IPC_EXCL|0666);
return shmid;
}
int get_old_shared_memory()
{
key_t key=get_key();
//申请新的共享内存
int shmid=shmget(key,4097,IPC_CREAT|0666);
return shmid;
}
shm1.cpp写入:
cpp
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "header.hpp"
int main()
{
//为了减小代码行数,系统调用的错误执行结果都没有判断
int shmid=get_new_shared_memory();
char* start_addr=(char*)shmat(shmid,nullptr,0);
mkfifo("./tmp_fifo",0664);
int fd=open("./tmp_fifo",O_RDONLY);
for (;;)
{
char ch;
ssize_t n=read(fd,&ch,1);
if (n==0||n<0)
break;
std::cout<<start_addr<<std::endl;
}
shmdt(start_addr);
shmctl(shmid,IPC_RMID,nullptr);
unlink("./tmp_fifo");
return 0;
}
shm2.cpp写入:
cpp
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "header.hpp"
int main()
{
//为了减小代码行数,系统调用的错误执行结果都没有判断
int shmid=get_old_shared_memory();
char* start_addr=(char*)shmat(shmid,nullptr,0);
int fd=open("./tmp_fifo",O_WRONLY);
for (;;)
{
std::cin>>start_addr;
write(fd,"",1);
}
shmdt(start_addr);
return 0;
}
运行结果:

我这个共享内存+管道代码最初版本写的有问题,下篇文章讲讲排错记录
共享内存的属性
man手册是这样说的:共享内存的属性存储在struct shmid_ds
cpp
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; /* Creation time/time of last
modification via shmctl() */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
struct ipc_perm {
key_t __key; /* Key supplied to shmget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions + SHM_DEST and
SHM_LOCKED flags */
unsigned short __seq; /* Sequence number */
};
注: struct shmid_ds内含struct ipc_perm,结构体嵌套
对于一个已经创建好的共享内存,其key存储在struct ipc_perm中,这是很自然的,因为操作系统要想管理共享内存,必须先描述共享内存再组织共享内存,描述共享内存需要结构体