我使用信号量( http://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem)在 C 中实现了 Reader/Writer 问题。
如果我将各个进程置于 sleep() 状态一秒钟,程序将按预期运行,但是如果我让它运行而不中断,我会得到如下信息:
writer wrote 5
writer wrote 10
reader reads the data:5
writer wrote 15
reader reads the data:15
reader reads the data:15
Semaphore with value of sid = 11599873 is killed
Semaphore with value of sid = 11632642 is killed
Semaphore with value of sid = 11665411 is killed
或者
writer wrote 5
writer wrote 10
writer wrote 15
reader reads the data:5
reader reads the data:15
reader reads the data:15
Semaphore with value of sid = 11599873 is killed
Semaphore with value of sid = 11632642 is killed
Semaphore with value of sid = 11665411 is killed
这仅仅是因为标准输出缓冲区乱序打印这些行,还是我的实现中存在竞争条件?
这是代码:
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include "sem.h"
#define N 3
#define BUFSIZE 1
#define PERMS 0666 //0666 - To grant read and write permissions
int *buffer;
int mutex,write_allowed,rd_count; /* semaphore variables
* mutex, write_allowed - binary semaphore -- critical section
* rd_count - counting semaphore */
void reading()
{
//perform read
int g;
g=*buffer;
printf("reader reads the data:%d\n",g);
}
int main()
{
int shmid,no=1,i;
int pid,n;
if((shmid=shmget(1000,BUFSIZE,IPC_CREAT| PERMS )) < 0)
{
printf("\n unable to create shared memory");
return;
}
if((buffer=(int*)shmat(shmid,(char*)0,0)) == (int*)-1)
{
printf("\n Shared memory allocation error\n");
exit(1);
}
// semaphore creation
if((mutex=semget(IPC_PRIVATE,1,PERMS | IPC_CREAT)) == -1)
{
printf("\n can't create mutex semaphore");
exit(1);
}
if((write_allowed=semget(IPC_PRIVATE,1,PERMS | IPC_CREAT)) == -1)
{
printf("\n can't create empty semaphore");
exit(1);
}
if((rd_count=semget(IPC_PRIVATE,1,PERMS | IPC_CREAT)) == -1)
{
printf("\ncan't create full semaphore");
exit(1);
}
// initialze the semaphore
sem_create(mutex,1);
sem_create(write_allowed,1);
sem_create(rd_count,0);
//forking a child
if((pid=fork()) < 0)
{
printf("\n Error in process creation");
exit(1);
}
// write process
if(pid > 0)
{
for(i=0;i<N;i++)
{
P(write_allowed);
//perform write
*buffer=*buffer+5;
printf("write wrote %d\n", *buffer);
//sleep(1);
V(write_allowed);
}
}
//read process
if(pid == 0)
{
for(i=0;i<N;i++)
{
P(mutex);
rd_count++;
if(1 == rd_count)
P(write_allowed);
V(mutex);
reading();
//sleep(1);
P(mutex);
rd_count--;
if(0==rd_count)
V(write_allowed);
V(mutex);
}
shmdt(0);
shmctl(shmid, IPC_RMID, NULL);
semkill(mutex);
semkill(write_allowed);
semkill(rd_count);
}
}
sem.h 文件:
/************************************************************************/
/* Operating Systems - Fall 2006
/* */
/* Semaphore library : sem.h */
/* */
/* Originally developed at KSU by a teaching assistant */
/* */
/* Description : The following library is a collection of */
/* routines for using binary semaphores in C: */
/* 1. seminit - to initialize a semaphore. */
/* 2. P - to perform a P(S) (wait) operation. */
/* 3. V - to perform a V(S) (signal) operation. */
/* 4. semkill - to remove a semaphore */
/* */
/* These routines call system routines: */
/* 1. semget - to get a semaphore */
/* 2. semctl - semaphore control operations */
/* 3. semop - semaphore operations */
/* */
/* Complete manual entries can be obtained by: */
/* man semctl | col -b | lpr */
/************************************************************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union arg{ /* This structure is used to call semctl */
int val;
struct semid_ds *buf;
char *array;
};
/*
* Create semaphore based on "key" parameter to "initval"
*/
void sem_create(int semid, int initval)
{
int semval;
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
}s;
s.val=initval;
if((semval=semctl(semid,0,SETVAL,s))<0)
printf("\n Erroe in executing semctl");
}
/*
* Remove semaphore with semaphore id (sid) from the kernel
*/
static void semkill (sid)
int sid;
{
if (semctl(sid,0,IPC_RMID,0) == -1)
perror("semctl (kill)");
printf("Semaphore with value of sid = %d is killed \n",sid);
}
/*
* Perform the designated "op" operation on the semaphore. If "op" is -1,
* then this implements the "P" operation; it decrements the value of the
* semaphore (semval) if it was >0,
* and blocks the caller if it was zero (semval==0)
* If "op" is 1, then this is simply added to current value of
* the semaphore ("V" operation).
*/
static void semcall(sid, op)
int sid;
int op;
{
struct sembuf sb;
sb.sem_num = 0; /* semaphore number within sid */
sb.sem_op = op;
sb.sem_flg = 0; /* blocking call */
if (semop(sid, &sb, 1) == -1)
perror("semop");
}
/*
* P operation on semaphore "sid". Should be called upon entry to critical
* region.
*/
static void P(sid)
int sid;
{
semcall(sid, -1);
}
/*
* V operation on semaphore "sid". Should be called upon exit from critical
* region.
*/
static void V(sid)
int sid;
{
semcall(sid, 1);
}