信号量和标准输出缓冲区

时间:2013-11-12 23:09:48

标签: c unix stdout semaphore race-condition

我使用信号量(http://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem)在C中实现了Reader / Writer问题。

如果我将各个进程暂停()一秒钟,程序按预期运行,但如果我让它运行而不中断我会得到这样的结果:

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);
}

1 个答案:

答案 0 :(得分:2)

您不会按rd_count++;增加信号量。 rd_count应该只是一个信号量ID。您需要使用某种使用信号量ID操作的函数来更改信号量的状态,信号量保存在两个进程之外的某个位置。

我也不熟悉sem_create(),但除非它是一个带参考参数的C ++函数,否则我怀疑它对你传递的变量有任何副作用。