善用搜索

【基础知识】进程通信之共享内存+信号量教程

2. 示例代码

新建semaphore.h文件

#ifndef __SEM_H__
#define __SEM_H__

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>

#define PATHNAME "./"
#define PROJ_ID 0x666

union semun
{
    int val; //单个信号的值 
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};


int create_sem_set(int nsem);

int get_sem_set(int nsem);

int init_sem_set(int sem_set_id, int which_sem);

int sem_p(int sem_set_id, int which_sem);

int sem_v(int sem_set_id, int which_sem);

int destroy_sem_set(int sem_set_id);

#endif 

新建semaphore.c文件

#include "semaphore.h"


static int sem_set(int nsem, int semflag)
{
    key_t key = ftok(PATHNAME, PROJ_ID);
    if (key < 0)
    {
        perror("ftok failure");
        exit(-1);
    }
    int sem_set_id = semget(key, nsem, semflag);
    if (sem_set_id < 0)
    {
        perror("semget failure");
        exit(-1);
    }
    return sem_set_id;
}


int create_sem_set(int nsem)
{
    if (nsem <= 0)
    {
        perror("nsem <= 0");
        exit(-1);
    }
    return sem_set(nsem, IPC_CREAT | IPC_EXCL | 0666);
}

int get_sem_set(int nsem)
{
    if (nsem <= 0)
    {
        perror("nsem <= 0");
        exit(-1);
    }
    return sem_set(nsem, IPC_CREAT);
}

int init_sem_set(int sem_set_id, int which_sem)
{
    union semun my_semun;
    my_semun.val = 1;//semun中val的值去设置信号集(sem_set)中单个sem的值
    int ret = semctl(sem_set_id, which_sem, SETVAL, my_semun);
    if (ret == -1)
    {
        perror("semctl error");
        exit(-1);
    }
    return 0;
}

static int sem_operatons(int sem_set_id, int which_sem, int op)
{
    struct sembuf sb;
    //sembuf is as follows:

    //unsigned short sem_num
    //short sem_op
    //short sem_flg

    sb.sem_num = which_sem;
    sb.sem_op = op;
    sb.sem_flg = SEM_UNDO;
    return semop(sem_set_id, &sb, 1);
}

int sem_p(int sem_set_id, int which_sem)
{ 
    return sem_operatons(sem_set_id, which_sem, -1);
}

int sem_v(int sem_set_id, int which_sem)
{ 
    return sem_operatons(sem_set_id, which_sem, +1);
}

int destroy_sem_set(int sem_set_id)
{
   int ret = semctl(sem_set_id, 0, IPC_RMID, NULL); 
   if (ret == -1)
   {
       perror("semctl failure");
       exit(-1);
   }

   return ret;
}

新建shm.h文件

#ifndef __SHM__
#define __SHM__

#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>


#define PATHNAME "./"
#define PROJ_ID 0x666



int create_shm(int sz);

int get_shm(int sz);

void* malloc_addr(int shm_id);

int free_addr(const void* addr);

int destroy_shm(int shm_id);


#endif 

新建shm.c文件

#include"shm.h"

static int shm(int sz, int flag)
{
    key_t key = ftok(PATHNAME, PROJ_ID);
    if (key == -1)
    {
        perror("ftok failure");
        exit(-1);
    }

    int shm_id = shmget(key, sz, flag);
    if (shm_id < 0)
    {
        perror("shmget failure");
        exit(-1);
    }
    return shm_id;
}

int create_shm(int sz)
{
    return shm(sz, IPC_CREAT | IPC_EXCL | 0666);
}

int get_shm(int sz)
{
    return shm(sz, IPC_CREAT);
}

void* malloc_addr(int shm_id)
{
    return shmat(shm_id, NULL, 0);
}

int free_addr(const void* addr)
{
    return shmdt(addr);
}

int destroy_shm(int shm_id)
{
   return shmctl(shm_id, IPC_RMID, NULL);     
}

新建test.c文件

#include"shm.h"
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include"semaphore.h"
typedef struct cPicInfo{
    int size;
    char state;
}cPicInfo;

typedef struct cPicBuf{
    char *picbuf;
    int *picbuf_size;
    char *picbuf_state; //0 :not use 1: will using 2: is using
}cPicBuf;

#define SHM_SIZE         (4096 + sizeof(cPicInfo))
#define PICBUF_NUM        (10)

cPicBuf* getfreebuf_frome_mem(char *sharebuf, int perpic_size)
{
    int i;
    cPicBuf picbuf[PICBUF_NUM];
    char *psharebuf = sharebuf + 1;
    for( i = 0; i <PICBUF_NUM; i++){
        picbuf[i].picbuf = psharebuf + i * SHM_SIZE;
        picbuf[i].picbuf_size = (int *)(picbuf[i].picbuf + ( SHM_SIZE - sizeof(cPicInfo)));
        picbuf[i].picbuf_state = (char *)(picbuf[i].picbuf_size) + sizeof(int);
        
        if(*picbuf[i].picbuf_state == 0){
            *picbuf[i].picbuf_state = 2;
            break;
        }
    }
    printf("get free i:%d\n",i);
    return i < PICBUF_NUM ?  &picbuf[i] : NULL;
}

cPicBuf* getcolbuf_frome_mem(char *sharebuf, int perpic_size)
{
    int i;
    cPicBuf picbuf[PICBUF_NUM];
    char *psharebuf = sharebuf + 1;
    for( i = 0; i <PICBUF_NUM; i++){
        picbuf[i].picbuf = psharebuf + i * SHM_SIZE;
        picbuf[i].picbuf_size = (int *)(picbuf[i].picbuf + ( SHM_SIZE - sizeof(cPicInfo)));
        picbuf[i].picbuf_state = (char *)(picbuf[i].picbuf_size) + sizeof(int);
        
        if(*picbuf[i].picbuf_state == 2){
            *picbuf[i].picbuf_state = 3;
            break;
        }
    }
    printf("get col i:%d\n",i);
    return i < PICBUF_NUM ?  &picbuf[i] : NULL;
}

int main()
{
    int ret;
   //创建信号量并初始化
    int sem_set_id = create_sem_set(2);
    init_sem_set(sem_set_id, 0);
    init_sem_set(sem_set_id, 1);
    //创建共享内存
    int shm_id = create_shm(SHM_SIZE * PICBUF_NUM + 1);

    //创建子进程
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork failure");
        exit(-1);
    }
    else if (pid == 0) //子进程
    {
        char* buf = (char*)malloc_addr(shm_id);
        int count = 0;
        cPicBuf* freebuf;
        
        buf[0] = 1;
        while(1)
        {
            //if(buf[0] == 1){    int ret = semctl(sem_set_id, which_sem, SETVAL, my_semun);
            if( 1 == (ret =semctl(sem_set_id, 1, GETVAL, NULL))){
                printf("zi ret: %d\n", ret);
;                count++;
                sem_p(sem_set_id, 0);    
                freebuf = getfreebuf_frome_mem(buf, SHM_SIZE);
                if(freebuf != NULL)
                    *freebuf->picbuf_size = count;
                buf[0] = 2;
                sem_v(sem_set_id, 0); 
                sem_p(sem_set_id, 1);
            }
            if(count == 10)
                break;
        }
        free_addr(buf);

    }
    else //父进程
    {
        char* buf = (char*)malloc_addr(shm_id);
        //usleep(500000);//让子进程先P操作
        cPicBuf* colbuf;
        int count1 = 0;
        while(1)
        {
            //if(buf[0] == 2){
            if( 0 == (ret = semctl(sem_set_id, 1, GETVAL, NULL))){
                printf("fu ret: %d\n", ret);
                count1++;
                sem_p(sem_set_id, 0); 
                colbuf = getcolbuf_frome_mem(buf, SHM_SIZE);
                if(colbuf != NULL)
                {
                    printf("picbuf_size :%d \n",*colbuf->picbuf_size);
                }
                buf[0] = 1;
                
                sem_v(sem_set_id, 0);  
                sem_v(sem_set_id, 1);                
            }
            if(count1 == 10)
                break;
        }
        
        free_addr(buf);
        destroy_shm(shm_id);
        destroy_sem_set(sem_set_id);
    }

    return 0;
}

新建Makefile文件

test:test.c semaphore.c shm.c
    gcc -o $@ $^
.PHONY:clean
clean:
    rm -f test
发表评论
退出移动版