【问题标题】:Semaphores and the standard out buffer信号量和标准输出缓冲区
【发布时间】:2013-11-12 23:09:47
【问题描述】:

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

如果我将各个进程置于 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);
}

【问题讨论】:

  • 我不知道你是不是在开玩笑。如果您没有发布其余代码,因为如果这表明那里也会出现问题。
  • 不开玩笑,我添加了sem.h 文件。
  • pre-ansi C?请告诉我你不是在 2013 年写的。
  • 不,2006 年的其他人。几乎一样糟糕。
  • 抛开最初的愤怒不谈,它的工作方式没有任何问题。您只是在一个循环中,因此没有sleep,该循环将在其时间片结束之前多次写入(或读取)。当你让它进入睡眠状态时,你就给了另一个进程一个安排和运行的机会。也就是说,有些代码很糟糕。不要将变量命名为“读取”和“写入”,因为它们是系统调用并会导致冲突。

标签: c unix stdout semaphore race-condition


【解决方案1】:

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

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

【讨论】:

  • 对不起,我应该更清楚。很多函数来自sem.h 文件。我会解决 rd_count 问题。
猜你喜欢
  • 1970-01-01
  • 2013-11-28
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多