C++学习笔记(46)

四、incache.cpp
// 多进程的生产消费者模型的生产者程序
#include "_public.h"
int main()
{
struct stgirl // 循环队列的数据元素是超女结构体。
{
int no;
char name[51];
};
using ElemType=stgirl;
// 初始化共享内存。
int shmid=shmget(0x5005, sizeof(squeue<ElemType,5>), 0640|IPC_CREAT);
if ( shmid ==-1 )
{
cout << "shmget(0x5005) failed.\n"; return -1;
}
// 把共享内存连接到当前进程的地址空间。
squeue<ElemType,5> *QQ=(squeue<ElemType,5> *)shmat(shmid,0,0);
if ( QQ==(void *)-1 )
{
cout << "shmat() failed\n"; return -1;
}
QQ->init(); // 初始化循环队列。
ElemType ee; // 创建一个数据元素。
csemp mutex; mutex.init(0x5001); // 用于给共享内存加锁。
csemp cond; cond.init(0x5002,0,0); // 信号量的值用于表示队列中数据元素的个数。
mutex.wait(); // 加锁。
// 生产 3 个数据。
ee.no=3; strcpy(ee.name,"西施"); QQ->push(ee);
ee.no=7; strcpy(ee.name,"冰冰"); QQ->push(ee);
ee.no=8; strcpy(ee.name,"幂幂"); QQ->push(ee);
mutex.post(); // 解锁。
cond.post(3); // 实参是 3,表示生产了 3 个数据。
shmdt(QQ); // 把共享内存从当前进程中分离。
}
五、outcache.cpp
// 多进程的生产消费者模型的消费者程序
#include "_public.h"
int main()
{
struct stgirl // 循环队列的数据元素是超女结构体。
{
int no;
char name[51];
};
using ElemType=stgirl;
// 初始化共享内存。
int shmid=shmget(0x5005, sizeof(squeue<ElemType,5>), 0640|IPC_CREAT);
if ( shmid ==-1 )
{
cout << "shmget(0x5005) failed.\n"; return -1;
}
// 把共享内存连接到当前进程的地址空间。
squeue<ElemType,5> *QQ=(squeue<ElemType,5> *)shmat(shmid,0,0);
if ( QQ==(void *)-1 )
{
cout << "shmat() failed\n"; return -1;
}
QQ->init(); // 初始化循环队列。
ElemType ee; // 创建一个数据元素。
csemp mutex; mutex.init(0x5001); // 用于给共享内存加锁。
csemp cond; cond.init(0x5002,0,0); // 信号量的值用于表示队列中数据元素的个数。
while (true)
{
mutex.wait(); // 加锁。
while (QQ->empty()) // 如果队列空,进入循环,否则直接处理数据。必须用循环,不能
用 if
{
mutex.post(); // 解锁。
cond.wait(); // 等待生产者的唤醒信号。
mutex.wait(); // 加锁。
}
// 数据元素出队。
ee = QQ->front(); QQ->pop();
mutex.post(); // 解锁。
// 处理出队的数据(把数据消费掉)。
cout << "no=" << ee.no << ",name=" << ee.name << endl;
usleep(100); // 假设处理数据需要时间,方便演示。
}
shmdt(QQ);
}
六、_public.h
#ifndef __PUBLIC_HH
#define __PUBLIC_HH 1
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
using namespace std;
// 循环队列。
template <class TT, int MaxLength>
class squeue
{
private:
bool m_inited; // 队列被初始化标志,true-已初始化;false-未初始化。
TT m_data[MaxLength]; // 用数组存储循环队列中的元素。
int m_head; // 队列的头指针。
int m_tail; // 队列的尾指针,指向队尾元素。
int m_length; // 队列的实际长度。
squeue(const squeue &) = delete; // 禁用拷贝构造函数。
squeue &operator=(const squeue &) = delete; // 禁用赋值函数。
public:
squeue() { init(); } // 构造函数。
// 循环队列的初始化操作。
// 注意:如果用于共享内存的队列,不会调用构造函数,必须调用此函数初始化。
void init()
{
if (m_inited!=true) // 循环队列的初始化只能执行一次。
{
m_head=0; // 头指针。
m_tail=MaxLength-1; // 为了方便写代码,初始化时,尾指针指向队列的最后一个位置。
m_length=0; // 队列的实际长度。
memset(m_data,0,sizeof(m_data)); // 数组元素清零。
m_inited=true;
}
}
// 元素入队,返回值:false-失败;true-成功。
bool push(const TT &ee)
{
if (full() == true)
{
cout << "循环队列已满,入队失败。\n"; return false;
}
// 先移动队尾指针,然后再拷贝数据。
m_tail=(m_tail+1)%MaxLength; // 队尾指针后移。
m_data[m_tail]=ee;
m_length++;
return true;
}
// 求循环队列的长度,返回值:>=0-队列中元素的个数。
int size()
{
return m_length;
}
// 判断循环队列是否为空,返回值:true-空,false-非空。
bool empty()
{
if (m_length == 0) return true;
return false;
}
// 判断循环队列是否已满,返回值:true-已满,false-未满。
bool full()
{
if (m_length == MaxLength) return true;
return false;
}
// 查看队头元素的值,元素不出队。
TT& front()
{
return m_data[m_head];
}
// 元素出队,返回值:false-失败;true-成功。
bool pop()
{
if (empty() == true) return false;
m_head=(m_head+1)%MaxLength; // 队列头指针后移。
m_length--;
return true;
}
// 显示循环队列中全部的元素。
// 这是一个临时的用于调试的函数,队列中元素的数据类型支持 cout 输出才可用。
void printqueue()
{
for (int ii = 0; ii < size(); ii++)
{
cout << "m_data[" << (m_head+ii)%MaxLength << "],value=" \
<< m_data[(m_head+ii)%MaxLength] << endl;
}
}
};
// 信号量。
class csemp
{
private:
union semun // 用于信号量操作的共同体。
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
int m_semid; // 信号量 id(描述符)。
// 如果把 sem_flg 设置为 SEM_UNDO,操作系统将跟踪进程对信号量的修改情况,
// 在全部修改过信号量的进程(正常或异常)终止后,操作系统将把信号量恢复为初始值。
// 如果信号量用于互斥锁,设置为 SEM_UNDO。
// 如果信号量用于生产消费者模型,设置为 0。
short m_sem_flg;
csemp(const csemp &) = delete; // 禁用拷贝构造函数。
csemp &operator=(const csemp &) = delete; // 禁用赋值函数。
public:
csemp():m_semid(-1){}
// 如果信号量已存在,获取信号量;如果信号量不存在,则创建它并初始化为 value。
// 如果用于互斥锁,value 填 1,sem_flg 填 SEM_UNDO。
// 如果用于生产消费者模型,value 填 0,sem_flg 填 0。
bool init(key_t key,unsigned short value=1,short sem_flg=SEM_UNDO);
bool wait(short value=-1);// 信号量的 P 操作,如果信号量的值是 0,将阻塞等待,直到信号量
的值大于 0。
bool post(short value=1); // 信号量的 V 操作。
int getvalue(); // 获取信号量的值,成功返回信号量的值,失败返回-1。
bool destroy(); // 销毁信号量。
~csemp();
};
#endif
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值