在linux的ubuntu下运行
头文件
shmdata.h
#ifndef _SHMDATA_H_HEADER
#define _SHMDATA_H_HEADER
#include "stdio.h"
#include "string.h"
#include "stdbool.h"
#define TEXT_LEN 10
#define MAX_SIZE 5
typedef struct queue {//循环队列
char buf[TEXT_LEN * MAX_SIZE];//字符串数组
int front;//队头指针,读指针
int rear;//队尾指针,写指针
int readlock;//值为1时读的临界区内存可访问,为0时不可访问
int writelock;//值为1时写的临界区内存可访问,为0时不可访问
int fullnum;//队列中写入字符串的内存单元个数
int emptynum;//队列中为空的内存单元个数
int firstbuild;//第一次创建队列的标志位,创建完成为1
} Queue;
bool enqueue(Queue *q, const char *data, size_t len);
bool dequeue(Queue *q, char *data);
void init_queue(Queue *q) {
q->front = 0;
q->rear = 0;
q->readlock=0;
q->writelock=1;
q->fullnum=0;
q->emptynum=1;
q->firstbuild=1;
memset(q->buf, 0, TEXT_LEN * MAX_SIZE);
}
bool enqueue(Queue *q, const char *data, size_t len) {
if (len > TEXT_LEN || len <= 0) {
puts("ERROR: the length of data is not supported!");
return false;
} else {
strncpy(q->buf + q->rear * TEXT_LEN, data, len);
q->rear = (q->rear + 1) % MAX_SIZE;
return true;
}
}
bool dequeue(Queue *q, char *data) {
strncpy(data, q->buf + q->front * TEXT_LEN, TEXT_LEN);
q->front = (q->front + 1) % MAX_SIZE;
return true;
}
#endif
consumer.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include "shmdata.h"
int main()
{
int running = 1;//程序是否继续运行的标志
void *shm = NULL;//分配的共享内存的原始首地址
int shmid;//共享内存标识符,创建共享内存
//寻找与生产者的共享内存,成功返回共享内存的ID,出错返回-1
shmid = shmget((key_t)1231, sizeof(Queue), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间(挂接操作)
//成功返回共享存储段的指针,出错返回-1
shm = shmat(shmid, 0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
//将内存地址赋值给队列
Queue *q= (Queue*)shm;
char ret[TEXT_LEN];
//读进程循环执行
while(running)
{
if(q->readlock=1&&q->fullnum!=0)
{
q->fullnum=q->fullnum-1;//申请一个存放数据的内存单元
q->readlock=0;//占用读的临界区内存空间
dequeue(q, ret); //消费者将内容从队头读出
if(strncmp(ret,"end",3)==0)//如果读到结束标志
{
q->readlock=1; // 释放读的临界区内存空间
q->emptynum=q->emptynum-1;//队列减少一个存放数据的内存单元
running=0;
}
printf("Consume the data: %s",ret);
q->readlock=1; // 释放读的临界区内存空间
q->emptynum=q->emptynum-1;//队列减少一个存放数据的内存单元
usleep(rand()%10000); //进程被阻塞0us到10ms之间的一个随机数,CPU运行其他消费者进程
}
else//有其他消费者进程在CPU运行,不能读取数据
usleep(rand()%10000); //进程被阻塞0us到10ms之间的一个随机数,CPU运行其他消费者进程
}
//把共享内存从当前进程中分离
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
producer.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shmdata.h"
int main()
{
int running = 1; //控制进程可以进行循环写操作
void *shm = NULL; //分配的共享内存的原始首地址
char buffer[BUFSIZ + 1];//用于保存输入的文本
int shmid; //共享内存的id
//创建共享内存,成功返回共享内存的ID,出错返回-1
shmid = shmget((key_t)1231, sizeof(struct queue), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间(挂接操作)
//成功返回共享存储段的指针,出错返回-1
shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
//将内存地址赋值给队列
struct queue* q= (Queue*)shm;
//初始化队列
if(q->firstbuild!=1)
{
init_queue(q);
printf("队列初始化\n");
}
//写进程循环执行
while(running)
{
//写的临界区不可用或者队列已满
while(q->writelock == 0||q->fullnum==MAX_SIZE)
{
if(q->fullnum==MAX_SIZE)
printf("Queue full\n");
usleep(rand()%10000);//因队列满进程被阻塞0us到10ms之间的一个随机数,等待消费者消费
printf("Waiting...\n");
}
q->emptynum=q->emptynum-1;//申请一个空的单元
q->writelock=0;//占用写的临界区内存空间
printf("Produce the data: ");
fgets(buffer, BUFSIZ, stdin);//获取数据到缓冲区
enqueue(q,buffer,TEXT_LEN); //向写临界区(队尾)中写入数据
q->writelock = 1;//释放写的临界区内存空间
q->fullnum=q->fullnum+1; //队尾增加一个存放数据的单元
//如果存放数据的单元既是队头又是队尾
//则在写操作完毕后释放读的临界区内存资源
if(q->fullnum==1)
q->readlock=1;
usleep(rand()%10000); //执行写操作一次后,进程被阻塞0us到10ms之间的一个随机数,CPU运行其他写进程
//输入了end,退出循环(程序)
if(strncmp(buffer, "end", 3) == 0)
running = 0;
}
//把共享内存从当前进程中分离
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
删除共享内存
delm.c
运行结果:
先运行生产者,再运行消费者
一个生产者,队列满:
一个生产者,一个消费者:
多个生产者,多个消费者:
用sleep()进行阻塞的测试结果:
用usleep()进行阻塞的测试结果: