信号量:
ipc.h
#ifndef _IPC_H
#define _IPC_H_
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <error.h>
#include <stdlib.h>
int sem_create(int);
int sem_open(int);
int sem_setval(int, int);
int sem_p(int);
int sem_v(int);
int sem_delete(int);
#endif
ipc.c
#include "ipc.h"
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int sem_create(int key)
{
int semid;
semid = semget(key, 1, IPC_CREAT|0666);
if(semid == -1)
exit(EXIT_FAILURE);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key, 0, 0);
if(semid == -1)
exit(EXIT_FAILURE);
return semid;
}
int sem_setval(int semid, int val)
{
int ret;
union semun sem_arg;
sem_arg.val = val;
if((ret = semctl(semid, 0, SETVAL, sem_arg)) == -1)
{
exit(EXIT_FAILURE);
}
return ret;
}
int sem_p(int semid)
{
struct sembuf buf;
int ret;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
if((ret = semop(semid, &buf, 1)) == -1)
{
exit(EXIT_FAILURE);
}
return ret;
}
int sem_v(int semid)
{
struct sembuf buf;
int ret;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
if((ret = semop(semid, &buf, 1)) == -1)
{
exit(EXIT_FAILURE);
}
return ret;
}
int sem_delete(int semid)
{
int ret;
ret = semctl(semid, 1, IPC_RMID, 0);
if(ret == -1)
{
exit(EXIT_FAILURE);
}
return ret;
}
共享内存:
shm_fifo.h
#ifndef _SHM_FIFO_H
#define _SHM_FIFO_H_
#include "ipc.h"
#include <sys/shm.h>
typedef struct shmfifo shmfifo_t;
typedef struct shmhead shmhead_t;
struct shmhead
{
unsigned int blksize; //块大小
unsigned int blocks; //总块数
unsigned int rd_index; //读索引
unsigned int wr_index; //写索引
};
struct shmfifo
{
shmhead_t *p_shm; //共享内存头部指针
char *p_payload; //有效负载的起始地址
int shmid; //共享内存IO
int sem_mutex; //用来互斥用的信号量
int sem_full; //用来控制共享内存是否满的信号量
int sem_empty; //用来控制共享内存是否空的信号量
};
shmfifo_t* shmfifo_init(int key,int blksize,int blocks);
void shmfifo_put(shmfifo_t *fifo,const void* buf);
void shmfifo_get(shmfifo_t *fifo,void *buf);
void shmfifo_destory(shmfifo_t *fifo);
#endif/* _SHM_FIFO_H */
shm_fifo.c
#include "shm_fifo.h"
#include <string.h>
shmfifo_t* shmfifo_init(int key, int blksize, int blocks)
{
shmfifo_t *fifo = NULL;
int shmid;
int size;
fifo = (shmfifo_t *)malloc(sizeof(shmfifo_t));
if(!fifo)
return NULL;
memset(fifo, 0, sizeof(shmfifo_t));
// 判断共享内存是否存在
shmid = shmget(key, 0, 0);
// 需要创建共享内存的大小
size = sizeof(shmhead_t) + blksize * blocks;
// 如果不存在
if(shmid == -1)
{
// 创建一个共享内存
fifo->shmid = shmget(key, size, IPC_CREAT | 0666);
if(fifo->shmid == -1)
exit(EXIT_FAILURE);
// 头部指针指向共享内存
fifo->p_shm = (shmhead_t *)shmat(fifo->shmid, NULL, 0);
if(fifo->p_shm == (shmhead_t*)-1)
exit(EXIT_FAILURE);
fifo->p_payload = (char*)(fifo->p_shm + 1);
// 设置信号量
fifo->sem_mutex = sem_create(key);
fifo->sem_full = sem_create(key+1);
fifo->sem_empty = sem_create(key+2);
//信号量初始化
sem_setval(fifo->sem_mutex, 1);
sem_setval(fifo->sem_full, blocks);
sem_setval(fifo->sem_empty, 0);
//头部初始化
fifo->p_shm->blksize = blksize;
fifo->p_shm->blocks = blocks;
fifo->p_shm->rd_index = 0;
fifo->p_shm->wr_index = 0;
}
// 如果存在
else
{
fifo->shmid = shmid;
//头部指针指向共享内存
fifo->p_shm = (shmhead_t*)shmat(fifo->shmid, NULL , 0);
if( fifo->p_shm == (shmhead_t*)-1 )
exit(EXIT_FAILURE);
fifo->p_payload = (char*)(fifo->p_shm + 1);
fifo->sem_mutex = sem_open(key);
fifo->sem_full = sem_open(key+1);
fifo->sem_empty = sem_open(key+2);
//读写索引初始化
fifo->p_shm->rd_index = 0;
fifo->p_shm->wr_index = 0;
}
return fifo;
}
//生产者
void shmfifo_put(shmfifo_t *fifo,const void* buf)
{
sem_p(fifo->sem_full);
sem_p(fifo->sem_mutex);
memcpy(fifo->p_payload+fifo->p_shm->blksize*fifo->p_shm->wr_index, buf, fifo->p_shm->blksize);
fifo->p_shm->wr_index = (fifo->p_shm->wr_index + 1) % fifo->p_shm->blocks;
sem_v(fifo->sem_mutex);
sem_v(fifo->sem_empty);
}
//消费者
void shmfifo_get(shmfifo_t *fifo,void* buf)
{
sem_p(fifo->sem_empty);
sem_p(fifo->sem_mutex);
memcpy(buf, fifo->p_payload+fifo->p_shm->blksize*fifo->p_shm->rd_index, fifo->p_shm->blksize);
fifo->p_shm->rd_index = (fifo->p_shm->rd_index + 1) % fifo->p_shm->blocks;
sem_v(fifo->sem_mutex);
sem_v(fifo->sem_full);
}
void shmfifo_destory(shmfifo_t *fifo)
{
sem_delete(fifo->sem_mutex);
sem_delete(fifo->sem_full);
sem_delete(fifo->sem_empty);
int shmid = fifo->shmid;
shmctl(fifo->shmid, IPC_RMID, 0);
free(fifo);
}
示例:
生产者:
#include "shm_fifo.h"
typedef struct stu
{
char name[32];
int age;
}STU;
int main(void)
{
shmfifo_t *fifo = shmfifo_init(1234,sizeof(STU),3);
int i;
STU s;
memset(&s, 0, sizeof(STU));
s.name[0] = 'A';
for(i=0; i<5; i++)
{
s.age = 20 + i;
shmfifo_put(fifo,&s);
s.name[0] = s.name[0] + 1;
printf("send ok\n");
}
return 0;
}
消费者:
#include "shm_fifo.h"
typedef struct stu
{
char name[32];
int age;
}STU;
int main(void)
{
shmfifo_t *fifo = shmfifo_init(1234,sizeof(STU),3);
int i;
STU s;
memset(&s, 0, sizeof(STU));
for(i=0; i<10; i++)
{
shmfifo_get(fifo,&s);
printf("recv:name = %s,age=%d\n",s.name,s.age);
}
shmfifo_destory(fifo);
return 0;
}
编译:
gcc -c ipc.c -o ipc.o -g
gcc -c shm_fifo.c -o shm_fifo.o -g
gcc -c client.c -o client.o -g
gcc -c server.c -o server.o -g
gcc client.o ipc.o shm_fifo.o -o client -lpthread -lrt -g
gcc server.o ipc.o shm_fifo.o -o server -lpthread -lrt -g