共享内存是IPC机制中的第二个。他允许连个不相关的进程访问同一块逻辑内存,能够有效地实现两个进程间数据传递。
int shmget(key_t key,sizr_t size,int shmflg);创建共享内存
key为共享内存段的命名,size为以字节为单位的内存容量,shmflg包含9比特权限标识,和创建文件的mode一样,由IPC_CREAT创建共享内存段时必须和权限标识按位或。
创建成功返回非负整数,失败返回-1.
void* shmat(int shm_id, void *shm_addr,int shmflg);//启动共享内存,连接地址空间
shm_id 为shmget返回的共享内的标识符;shm_addr指定的事当前进程中的地址位置。通常是个空指针,标识让系统来选择共享内存出现的地址;shmflg有两个可能的取值SHM_RND(和shm_addr联合使用控制共享内存连接地址)和SHM_RDONLY(使连接的内存为只读)
shmdt 作用是将共享内存从进程中分离,成功时为0,失败返回-1
int shmctl(int shm_id,int command,struct shmid_ds *buf); 共享内存控制函数
shm_id 是shmget返回的共享内存标识符;command是要采取的动作,可以取3个值;buf是一个指针,包含共享内存模式和访问权限的结构。
我们创建一个shm1.c(消费者) shm2.c(生产者)和一个分发共享内存头文件shm_com.h
shm_com.h
#define TEXT_SZ 2048
struct shared_usr_st
{
int written_by_you;
char some_text[TEXT_SZ];
};
shm1.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
int running = -1;
void * shared_memory = (void*)0;
struct shared_usr_st *shared_stuff;
int shmid;
srand((unsigned int)getpid());
//建立共享内存,标识为1234
shmid = shmget((key_t)1234,sizeof(struct shared_usr_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_usr_st *)shared_emory;
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);
//拿出产品后将标识置0
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,"chmctl(IPC_RMID) failed\n");exit(EXIT_FAILURE);}
exit(EXIT_SUCCESS);
}
shm2.c
#define BUFSIZ 2048
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
int running = -1;
void * shared_memory = (void*)0;
struct shared_usr_st *shared_stuff;
char buffer[BUFSIZ];
in shmid;
shmid = shmget((key_t)1234,sizeof(struct shared_usr_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_usr_st *)shared_emory;
//生产者向共享内存空间发放产品
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);
//放入产品后将标识置1
shared_stuff->written_by_you = 1;
if(strncmp(shared_stuff->some_text,"end",3)==0)
{running = 0;}
}
}
if(shmdt(shared_memory)==-1)
{fprintf(stderr,"shmdt failed\n");exit(EXIT_FAILURE);}
exit(EXIT_SUCCESS);
}
输出结果:
./shm1 &
Memory attached at 8FC35000
./shm2
Memory attached at D2485000
Enter some text: neil
You wrote: neil
waiting for client...
waiting for client...
Enter some text: test
You wrote: test
waiting for client...
Enter some text: on
You wrote: on
waiting for client...
waiting for client...
waiting for client...
Enter some text: shared_memmory!!!
You wrote: shared_memmory!!!
waiting for client...
Enter some text: end
有一点比较疑惑,输出的内存地址为什么不相同,按理说应该相同的
扩展的话可以做不止一个产品的生产者消费者问题
这里同步标志位为written_by_you 是通过忙等待来达到同步效果,非常缺乏效率,在实际应用中应该会用信号量或者消息传递等来实现有效的同步机制。