@codejan
2018-11-13T12:44:33.000000Z
字数 5014
阅读 1702
操作系统
利用信号量机制, 实现生产者与消费者问题.
ipcs
可以查看目前系统的共享内存、信号量, 队列信息. 通过设置fullBuffer, emptyBuffer信号量解决生产者-消费着问题. 如果把fullBuffer和mutex的P操作顺序互换, 可能会引起死锁.
伪代码如下:
Class BoundedBudder {
mutex = new Semaphore(1);
fullBuffer = new Semaphore(0);
emptyBuffer = new Semphore(n);
}
BoundedBudder::Producer(c) {
emptyBuffer->P();
mutex->P();
add c to the buffer;
mutex->V();
fullBuffer->V();
}
BoundedBudder::Consumer(c) {
fullBuffer->P();
mutex->P();
remove c from the buffer;
mutex->V();
emptyBuffer->V();
}
源代码pv.h
和pv.c
实现P,V操作, 其他程序使用#include<pv.h>
调用.
源代码producter.c
先获取信号量和共享内存, 设置共享缓冲区. 然后模拟生产者的行为, 每次生产一个随机数存放在缓冲区, 总共打印 20 次, 每次延迟一秒.
源代码 consumer.c
先获取信号量和共享内存, 设置共享缓冲区. 然后模拟消费者的行为, 每次从缓冲区中取出一个数打印, 总共取 20 次, 每次延迟一秒.
空文件 file_for_key
被用于产生、获取信号量和共享内存.
利用makefile
指定编译顺序
运行 make
之后, 得到三个可执行文件 sem_init, producter, consumer
. 运行make clean
可以清除这三个文件
在终端中先运行 sem_init
, 然后在新开的终端上运行 producter
和 consumer
, 通过观察各个终端上的输
出, 可以判断是否符合预期.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define BUFFER_SIZE 10
#define SHM_SIZE 102
#define PRODUCT_NUM 25
void
P (int sem_id);
void
V (int sem_id);
#include "pv.h"
void
P (int sem_id)
{
struct sembuf semop_buf;
semop_buf.sem_num = 0;
semop_buf.sem_op = -1;
semop_buf.sem_flg = 0;
if (semop (sem_id, &semop_buf, 1) == -1)
{
perror ("PP"); //perror - print a system error message
exit (0);
}
}
void
V (int sem_id)
{
struct sembuf semop_buf;
semop_buf.sem_num = 0;
semop_buf.sem_op = 1;
semop_buf.sem_flg = 0;
if (semop (sem_id, &semop_buf, 1) == -1)
{
perror ("VV");
exit (0);
}
}
void
showval (int sem_a, int sem_b)
{
int val_a, val_b;
val_a = semctl (sem_a, 0, GETVAL);
val_b = semctl (sem_b, 0, GETVAL);
printf ("process %d: %d %d\n", getpid (), val_a, val_b);
if (val_a == 1 && val_b == 1)
exit (0);
}
#include "pv.h"
int
main ()
{
int sem_empty, sem_full;
key_t key[2];
//ftok - convert a pathname and a project identifier to a System V IPC key
key[0] = ftok ("file_for_key", 1);
key[1] = ftok ("file_for_key", 2);
printf ("key: %x %x\n", key[0], key[1]);
/*
semget - get a System V semaphore set identifier
RETURN VALUE
If successful, the return value will be the semaphore set identifier (a non‐
negative integer), otherwise, -1 is returned, with errno indicating the
error.
*/
sem_empty = semget (key[0], 0, 0);
sem_full = semget (key[1], 0, 0);
if (sem_empty < 0 || sem_full < 0)
{
printf ("There are not sem_empty or sem_full!\n");
exit(1);
}
int shm_id = shmget (key[0], 0, 0);
if (shm_id)
printf ("shm id is %d\n", shm_id);
else
{
printf ("Key %d have not SHARE MEMORY!\n", key[0]);
exit(1);
}
int *buffer;
int *in;
int *out;
/*
shmat, shmdt - System V shared memory operations
RETURN VALUE
On success, shmat() returns the address of the attached shared memory seg‐
ment; on error, (void *) -1 is returned, and errno is set to indicate the
cause of the error.
*/
in = (int *) shmat(shm_id, NULL, 0);
out = in + 1;
buffer = out + 1;
int i = 0;
/*
producer的过程:
1. 对信号量sem_empty执行P操作
2. 向缓冲区中in指针的位置放入一个随机数并打印
3. 把in指针向前移动一个单位
4. 对信号量sem_full执行V操作
5. 计数器加1
6. 如此往复, 直到生产完成指定数量为止
*/
while (1)
{
P(sem_empty);
buffer[*in] = random() % 1000;
printf ("%d\n", buffer[*in]);
*in = (*in + 1) % BUFFER_SIZE;
V(sem_full);
i++;
if (i > PRODUCT_NUM)
break;
}
return 0;
}
#include "pv.h"
int
main ()
{
int sem_empty, sem_full;
key_t key[2];
//ftok - convert a pathname and a project identifier to a System V IPC key
key[0] = ftok ("file_for_key", 1);
key[1] = ftok ("file_for_key", 2);
printf ("key: %x %x\n", key[0], key[1]);
/*
semget - get a System V semaphore set identifier
RETURN VALUE
If successful, the return value will be the semaphore set identifier (a non‐
negative integer), otherwise, -1 is returned, with errno indicating the
error.
*/
sem_empty = semget (key[0], 0, 0);
sem_full = semget (key[1], 0, 0);
if (sem_empty < 0 || sem_full < 0)
{
printf ("There are not sem_empty or sem_full!\n");
exit(1);
}
int shm_id = shmget (key[0], 0, 0);
if (shm_id)
printf ("shm id is %d\n", shm_id);
else
{
printf ("Key %d have not SHARE MEMORY!\n", key[0]);
exit(1);
}
int *buffer;
int *in;
int *out;
/*
shmat, shmdt - System V shared memory operations
RETURN VALUE
On success, shmat() returns the address of the attached shared memory seg‐
ment; on error, (void *) -1 is returned, and errno is set to indicate the
cause of the error.
*/
in = (int *) shmat(shm_id, NULL, 0);
out = in + 1;
buffer = out + 1;
int i = 0;
/*
producer的过程:
1. 对信号量sem_empty执行P操作
2. 向缓冲区中in指针的位置放入一个随机数并打印
3. 把in指针向前移动一个单位
4. 对信号量sem_full执行V操作
5. 计数器加1
6. 如此往复, 直到生产完成指定数量为止
*/
while (1)
{
P(sem_empty);
buffer[*in] = random() % 1000;
printf ("%d\n", buffer[*in]);
*in = (*in + 1) % BUFFER_SIZE;
V(sem_full);
i++;
if (i > PRODUCT_NUM)
break;
}
return 0;
}
all: sem_init producer consumer
pv.o: pv.c
gcc -Wall -O2 -c pv.c
sem_init: sem_init.c
gcc -Wall -O2 sem_init.c -o sem_init
producer: producer.c pv.o
gcc -Wall -O2 producer.c pv.o -o producer
consumer: consumer.c pv.o
gcc -Wall -O2 consumer.c pv.o -o consumer
clean:
rm -f pv.o sem_init producer consumer \
sem_init.c~ producer.c~ consumer.c~ pv.c~ pv.h~