课设二 使用IPC机制实现“生产者-过滤者-消费者”问题

@

要求

学习Linux进程间通信机制,使用信号量和共享内存实现进程同步问题“生产者-过滤者-消费者”问题。具体要求:
1.创建信号量集,实现同步互斥信号量。
2.创建共享内存,模拟存放产品的公共缓冲池。
3.创建并发进程,实现进程对共享缓冲池的并发操作。生产者生产产品后放入缓冲池,过滤者取出产品,对产品过滤(可自己设计,如对产品值进行+1)再放入缓冲池,消费者将过滤后的产品取走。可创建一个或两个缓冲池。

知识梳理

生产者-过滤者-消费者问题

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

关键在于:生产者放入产品之后才解锁了消费者消费产品的过程,消费者拿出产品之后才解锁了生产者生产产品的过程。

信号量和信号量集

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。
当利用信号量机制解决了单个资源的互斥访问后,我们讨论如何控制同时需要多个资源的互斥访问。信号量集是指同时需要多个资源时的信号量操作。

信号量的pv操作

信号量是个被保护的量,只有P、V操作和信号量初始化操作才能访问和改变它的值。
P操作和V操作定义如下,其中S为信号量值:

共享内存

共享存储

共享存储操作适得两个或两个以上的进程可以共用一段物理内存(一般情况下,两个进程的数据区是完全独立的,父进程用fork创建子进程后,子进程会复制父进程数据到自己的数据区)。

(1)创建共享内存

include<sys/shm.h>

int shmget(key_t key,size_t size, int permflags);

参数key是共享内存的标识,size是共享内存段的最小字节数,permflags是访问权限,值的设置同semget一样。

(2)共享内存的控制

include<sys/shm.h>

int shmctl(int shmid, int command, struct shmid_ds *shm_stat);

该函数semctl相似,command可设为IPC_STAT,IPC_SET,IPC_RMID。参数shm_stat指向存放属性的结构体,具体内容请参考手册。

(3)共享内存的附接和断开

#include<sys/shm.h>

void *shmat(int shmid, const void *addr, int shmflags);

int shmdt(const void *addr);

由于两个函数需指出进程地址空间中的地址,因此比较复杂。简化的方法是将shmat中的地址设为NULL。

**P (S)

{
S=S-1;
若S<0,将该进程状态置为等待状态,然后将该进程的PCB插入相应的S信号量等待 队列末尾,直到有其他进程在S上执行V操作为止;
}**

V (S)
{
S = S + 1 ;
若S<=0,释放在S信号量队列中等待的一个进程,将其状态改变为就绪态,并将其插 入就绪队列;然后,执行本操作的进程继续执行;
}

代码实现



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

#include <stddef.h>
#include <sys/shm.h>
#include <string.h>

#define TEXT_SIZE 1024


union union_semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}ctl_arg;

/*struct sembuf {
unsigned short sem_num;
short sem_op;
short sem_flg;
};*/

struct databuf {
int written;
char text[TEXT_SIZE];
};

static int shmid, semid_full, semid_empty, semid_zuse;

void initshm(struct databuf**p) {
//\u521b\u5efa\u5171\u4eab\u5185\u5b58
shmid = shmget((key_t)4321, sizeof(struct databuf), 0600 | IPC_CREAT);
if (shmid == -1) {
printf("shmget failed!\n");
return;
}
//\u8fde\u63a5\u5230\u5f53\u524d\u8fdb\u7a0b\uff0c\u8fd4\u56de\u6307\u5411\u7b2c\u4e00\u4e2a\u5b57\u8282\u7684\u6307\u9488
void *shm = shmat(shmid, NULL, 0);
if (shm == (void *)-1) {
printf("shmat failed!\n");
return;
}
printf("\nmemory attached at %d\n", (int)shm);

shm = *p;

}

void setdata(struct databuf**p) {

}
int initsem(key_t semkey) {
//\u521b\u5efa\u4fe1\u53f7\u91cf\u96c6\uff0c\u5e76\u4e14\u521d\u59cb\u5316
printf("\ninitsem running...");
int tmp = semget(semkey, 1, 0600 | IPC_CREAT | IPC_EXCL);
if (tmp == -1) {
printf("semget create failed!");
return;
}
printf("semid %d created successful", tmp);
return tmp;
}
void remobj(void) {
if (semctl(semid_empty, IPC_RMID, 0) == -1)	printf("\nremctl remobj error\n");
else printf("\nremctl delete success");
if (semctl(semid_full, IPC_RMID, 0) == -1)	printf("\nremctl remobj error\n");
else printf("\nremctl delete success");
}

int P(int semid) {
struct sembuf p_buf;
p_buf.sem_num = 0;
p_buf.sem_op = -1;
p_buf.sem_flg = SEM_UNDO;
if (semop(semid, &p_buf, 1) == -1) {
perror("p(semid) failed");
exit(1);
}
return 1;
}

int V(int semid) {
struct sembuf p_buf;
p_buf.sem_num = 0;
p_buf.sem_op = 1;
p_buf.sem_flg = SEM_UNDO;
if (semop(semid, &p_buf, 1) == -1) {
perror("p(semid) failed");
exit(1);
}
return 1;
}

void producter() {
//while (1) {
//if (P(semid)) {
P(semid_empty);
P(semid_zuse);
struct databuf *p = NULL;
//\u6d4b\u8bd5\uff0c\u653e\u5165\u6570\u636e
void *shm = shmat(shmid, NULL, 0);
if (shm == (void *)-1) {
printf("producter shmat failed!\n");
}
printf("\nproducter get shm scuess!");

p = (struct databuf *)shm;
//printf("\nplease input something:");
strcpy(p->text, "Apple");
printf("\nGet data success!");
sleep(10);
V(semid_zuse);
V(semid_full);
//}
//}
}

void filter() {
while (1) {
printf("\nfilter running...");
sleep(10);
}
}

void consumer() {
/*while(1){

}*/
//\u6d4b\u8bd5\uff0c\u8bfb\u51fa\u6570\u636e
while (1) {
//if (P(semid)) {
P(semid_full);
P(semid_zuse);
struct databuf *p = NULL;

void *shm = shmat(shmid, 0, 0);
if (shm == (void *)-1) {
printf("consumer shmat failed!\n");
}
printf("\ncomsumer get shm scuess!");

p = (struct databuf *)shm;
printf("\nYou wirte is %s", p->text);
V(semid_zuse);
V(semid_empty);

}
}

int main() {
key_t semkey, shmkey;
struct databuf *buf;
initshm(&buf);
semid_full = initsem(116);
semid_empty = initsem(117);
semid_zuse = initsem(118);


pid_t fpid = fork();

if (fpid < 0) {
printf("error in fork!");
}
else if (fpid == 0) {
producter();
}
else {
sleep(5);
pid_t fpid2 = fork();
if (fpid2 < 0)	printf("error in fork!");
else if (fpid2 == 0)	filter();
else	consumer();
}

remobj();

}

posted @ 2020-07-13 21:09  treblez  阅读(818)  评论(0编辑  收藏  举报