赞
踩
在linux系统中,每个进程都有独立的虚拟空间地址,通过MMU地址转换将虚拟地址与物理地址进行映射,每个进程相同的虚拟地址空间都会映射到不同的物理地址,每个进程在物理内存空间都是相互独立和隔离的。
不同的进程之间如果需要相互通信,该怎么办?因为不同的进程在物理内存上是相互隔离的,所以需要借助第三方工具来完成进程间通信。其实进程间通信的本质就是交换数据,进程间交换数据有三种方式:通过文件、通过内核、共享内存。
共享内存是由IPC为进程创建的一个特殊的地址范围,出现在该进程的地址空间中,其他进程可以将同一段共享内存连接到他们自己的地址空间中。所有进程都可以访问共享内存中的地址,就好像他们是由malloc分配的一样。如果一个进程向共享内存中写了数据,那么其他进程将立刻能够看到。
该函数用来创建/获取共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
该函数将shmid标识的共享内存引入到当前进程的虚拟地址空间
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
共享内存的读写就要注意共享内存多进程访问同步,一般可以通过信号量、互斥锁、文件锁等配合使用,防止数据的踩踏。
该函数解除内存映射,将共享内存分离出当前进程的地址空间
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
注意,函数shmdt仅仅是使进程和共享内存脱离关系,将共享内存的引用计数减1,并为删除共享内存。通过#ipc -m就可查看某个IPC对象的状态,其中“连接数”就是表示该共享内存对象被引用的计数。
上面看到,shmdt仅仅是使进程和共享内存脱离关系,并未删除共享内存。当共享内存的引用次数未0,可以调用shmctl的IPC_RMID命令才会删除共享内存。或者进程结束后,也会被删除掉。
shmctl获取/设置共享内存对象属性
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
更多的cmd可以通过man shmct去查看。
下面是一个简单的生产者-消费者模型,生产者producer进程负责将用户输入的数据写到共享内存中,消费者customer进程负责将共享内存中的读出来并打印出来。下面的程序示例通过共享内存中的变量written_by_you标记进行一个读写的同步,保证读写操作是互斥的。
//share.h
#define TEXT_SZ 2048
struct shared_use_st
{
int written_by_you;
char some_text[TEXT_SZ];
};
//customer.c #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "share.h" int main() { int running = 1; void *shared_memory = (void *)0; struct shared_use_st *shared_stuff; int shmid; srand((unsigned int)getpid()); shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT); if (shmid == -1) { fprintf(stderr, "shmget failed\n"); exit(EXIT_FAILURE); } shared_memory = shmat(shmid, (void *)0, 0); if (shared_memory == (void *)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("Memory attached at %X\n", (int)shared_memory); shared_stuff = (struct shared_use_st *)shared_memory; shared_stuff->written_by_you = 0; while(running) { if (shared_stuff->written_by_you) { printf("You wrote: %s", shared_stuff->some_text); sleep( rand() % 4 ); shared_stuff->written_by_you = 0; if (strncmp(shared_stuff->some_text, "end", 3) == 0) { running = 0; } } } if (shmdt(shared_memory) == -1) { fprintf(stderr, "shmdt failed\n"); exit(EXIT_FAILURE); } if (shmctl(shmid, IPC_RMID, 0) == -1) { fprintf(stderr, "shmctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } printf("customer exit.\n"); exit(EXIT_SUCCESS); }
//producer.c #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "share.h" int main() { int running = 1; void *shared_memory = (void *)0; struct shared_use_st *shared_stuff; char buffer[BUFSIZ]; int shmid; shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT); if (shmid == -1) { fprintf(stderr, "shmget failed\n"); exit(EXIT_FAILURE); } shared_memory = shmat(shmid, (void *)0, 0); if (shared_memory == (void *)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("Memory attached at %X\n", (int)shared_memory); shared_stuff = (struct shared_use_st *)shared_memory; while(running) { while(shared_stuff->written_by_you == 1) { sleep(1); printf("waiting for client...\n"); } printf("Enter some text: "); fgets(buffer, BUFSIZ, stdin); strncpy(shared_stuff->some_text, buffer, TEXT_SZ); shared_stuff->written_by_you = 1; if (strncmp(buffer, "end", 3) == 0) { running = 0; } } if (shmdt(shared_memory) == -1) { fprintf(stderr, "shmdt failed\n"); exit(EXIT_FAILURE); } printf("producer exit.\n"); exit(EXIT_SUCCESS); }
参考资料
[1]嵌入式C语音自我修养,王立涛
[2]大连理工大学《嵌入式软件设计》慕课
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。