/* 3. 共享存储的创建、附接和断接
由父进程建立一块共享存储区,并创建两个子进程p1,p2,父进程负责查询存储区状态,以及删除该存储区。
子进程p1链接到该共享存储区,然后向存储区写入数据,然后断开链接。
子进程p1链接到该共享存储区,从存储区读数据,然后断开链接。
注意:为了便于各进程对存储区访问的同步,这里使用信号量方法。
**/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "sem_com.c"
#define SIZE 1024
int main()
{
int sem_id;
key_t sem_key;
sem_key=ftok(".",'a');
//以0666且create mode创建一个信号量,返回给sem_id
sem_id=semget(sem_key,1,0666|IPC_CREAT);
//将sem_id设为1
init_sem(sem_id,1);
int shmid ;
char *shmaddr ;
struct shmid_ds buf ;
int flag = 0 ;
int pid ;
shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;//创建共享存储区
if ( shmid < 0 )
{
perror("get shm ipc_id error") ;
return -1 ;
}
pid = fork() ;
if ( pid == 0 ) //子进程p1
{
sem_p(sem_id); // P操作
shmaddr = (char *)shmat( shmid, NULL, 0 ) ;//链接到存储区
if ( (int)shmaddr == -1 )
{
perror("shmat addr error") ;
return -1 ;
}
strcpy( shmaddr, "Hi, I am child process!\n") ;//向存储区写数据
shmdt( shmaddr ) ;//断开链接
sem_v(sem_id); // V操作
} else if ( pid > 0) {//父进程
pid = fork();
if(pid == 0) { //子进程p2
sem_p(sem_id); //P操作
shmaddr = (char *)shmat( shmid, NULL, 0 ) ;//链接到存储区
if ( (int)shmaddr == -1 )
{
perror("shmat addr error") ;
return -1 ;
}
printf("%s", shmaddr) ;//读取存储区数据
shmdt( shmaddr ) ;//断开链接
sem_v(sem_id); //V操作
}
else if(pid>0)//父进程
{
sleep(1);
sem_p(sem_id); //P操作
flag = shmctl( shmid, IPC_STAT, &buf) ;//读取存储区状态到buf中
if ( flag == -1 )
{
perror("shmctl shm error") ;
return -1 ;
}
printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;
printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ;
printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;
printf("shm_segsz =%d \n", buf.shm_perm.mode );
shmdt( shmaddr) ;//断开链接
shmctl(shmid, IPC_RMID, NULL) ;//删除该存储区
sem_v(sem_id); //V操作
}
}else{
perror("fork error") ;
shmctl(shmid, IPC_RMID, NULL) ;
}
return 0 ;
}
//sem_com.c
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
// 将信号量sem_id设置为init_value
int init_sem(int sem_id,int init_value) {
union semun sem_union;
sem_union.val=init_value;
if (semctl(sem_id,0,SETVAL,sem_union)==-1) {
perror("Sem init");
exit(1);
}
return 0;
}
// 删除sem_id信号量
int del_sem(int sem_id) {
union semun sem_union;
if (semctl(sem_id,0,IPC_RMID,sem_union)==-1) {
perror("Sem delete");
exit(1);
}
return 0;
}
// 对sem_id执行p操作
int sem_p(int sem_id) {
struct sembuf sem_buf;
sem_buf.sem_num=0;//信号量编号
sem_buf.sem_op=-1;//P操作
sem_buf.sem_flg=SEM_UNDO;//系统退出前未释放信号量,系统自动释放
if (semop(sem_id,&sem_buf,1)==-1) {
perror("Sem P operation");
exit(1);
}
return 0;
}
// 对sem_id执行V操作
int sem_v(int sem_id) {
struct sembuf sem_buf;
sem_buf.sem_num=0;
sem_buf.sem_op=1;//V操作
sem_buf.sem_flg=SEM_UNDO;
if (semop(sem_id,&sem_buf,1)==-1) {
perror("Sem V operation");
exit(1);
}
return 0;
}