共享存储的创建、附接和断接

/* 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;
}

 

posted @ 2014-11-14 19:39  wonglou  阅读(678)  评论(0)    收藏  举报