Demo entry 6732863

1

   

Submitted by anonymous on Apr 16, 2018 at 03:25
Language: C. Code size: 5.9 kB.

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

#define SEMPERM 0600
#define TRUE 1
#define FALSE 0

typedef union   _semun {
             int val;
             struct semid_ds *buf;
             ushort *array;
             } semun;

int initsem (key_t semkey, int n) {
   int status = 0, semid;
   if ((semid = semget (semkey, 1, SEMPERM | IPC_CREAT | IPC_EXCL)) == -1)
   {
       if (errno == EEXIST)
                semid = semget (semkey, 1, 0);
   }
   else
   {
       semun arg;
       arg.val = n;
       status = semctl(semid, 0, SETVAL, arg);
   }
   if (semid == -1 || status == -1)
   {
       perror("initsem failed");

       return (-1);
   }
   return (semid);
}

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)
   {
      printf("p(semid) failed");
      exit(1);
   }
   return (0);
}

int v (int semid) {
   struct sembuf v_buf;
   v_buf.sem_num = 0;
   v_buf.sem_op = 1;
   v_buf.sem_flg = SEM_UNDO;
   if (semop(semid, &v_buf, 1) == -1)
   {
      printf("v(semid) failed");
      exit(1);
   }
   return (0);
}

// Shared variable by file
void reset(char *fileVar) {
// fileVar라는 이름의 텍스트 화일을 새로 만들고 0값을 기록한다.
  if(access(fileVar, F_OK) == -1) { //fileVar라는 이름의 텍스트 파일의 존재 여부 검사, 존재하지않는다면 생성
    FILE *fp; 

    fp = fopen(fileVar, "w"); 
    
    time_t recordedTime; //현재시간을 가져옴(읽는 시간 제외)
    time(&recordedTime);
    fprintf(fp, "Reader PID : %d Recorded Time : %s %d\n", getpid(), ctime(&recordedTime), 0); //초기 AR, WR, AW, WW 값을 0으로 초기화

    fclose(fp);
  } 
}

void Store(char *fileVar,int i) {
// fileVar 화일 끝에 i 값을 append한다.
  FILE *fp;

  fp = fopen(fileVar, "a");
  
  time_t recordedTime; //현재시간을 가져옴(읽는 시간 제외)
  time(&recordedTime);
  fprintf(fp, "Reader PID : %d Recorded Time : %s %d\n", getpid(), ctime(&recordedTime), i); //값이 변화할 때마다 저장
  
  fclose(fp);
}

int Load(char *fileVar) {
// fileVar 화일의 마지막 값을 읽어 온다.
  FILE *fp;

  fp = fopen(fileVar, "r");
  int fileData;
  fseek(fp, -4, SEEK_END); //파일 끝에서 4byte앞으로 이동
  fscanf(fp,"%d",&fileData); //파일 마지막 값을 읽음
  fclose(fp);

  return fileData;
}

void add(char *fileVar, int i) {
// fileVar 화일의 마지막 값을 읽어서 i를 더한 후에 이를 끝에 append 한다.
  int fileData = Load(fileVar);
  fileData += i;
  Store(fileVar, fileData);
}

void sub(char *fileVar,int i) {
// fileVar 화일의 마지막 값을 읽어서 i를 뺀 후에 이를 끝에 append 한다.
  int fileData = Load(fileVar);
  fileData -= i;
  Store(fileVar, fileData);
}

// Class Lock
typedef struct _lock { 
   int semid;
} Lock;

void initLock(Lock *l, key_t semkey) {
   if ((l->semid = initsem(semkey,1)) < 0) { 
   // 세마포를 연결한다.(없으면 초기값을 1로 주면서 새로 만들어서 연결한다.)
      exit(1);
    }
}

void Acquire(Lock *l) {
   p(l->semid);
}

void Release(Lock *l) {
   v(l->semid);
}

// Class CondVar
typedef struct _cond {
   int semid;
   char *queueLength;
} CondVar;

void initCondVar(CondVar *c, key_t semkey, char *queueLength) {
   c->queueLength = queueLength;
   reset(c->queueLength); // queueLength=0
   if ((c->semid = initsem(semkey,0)) < 0) {
   // 세마포를 연결한다.(없으면 초기값을 0로 주면서 새로 만들어서 연결한다.)
      exit(1); 
    }
}

void Wait(CondVar *c, Lock *lock) {
   add(c->queueLength, 1); //signal의 오류를 없애기위해 lock을 release하기 전에 queueLength를 하나 증가 
   Release(lock);
   p(c->semid);
   Acquire(lock);
}

void Signal(CondVar *c) {
  if(Load(c->queueLength) > 0) {
    v(c->semid);
    sub(c->queueLength, 1);
  }
}

void Broadcast(CondVar *c) {
  while(Load(c->queueLength) > 0) {
    v(c->semid);
    sub(c->queueLength, 1);
  }
}

int main(int argc, char* argv[]) {
   key_t semkey = 0x200; 
   key_t semRKey = 0x300;
   key_t semWKey = 0x400;
   //  서버에서 작업할 때는 자기 학번 등을 이용하여 다른 사람의 키와 중복되지 않게 해야 한다.
   //  실행하기 전에 매번 세마포들을 모두 지우거나 아니면 다른 semkey 값을 사용해야 한다.
   //  $ ipcs                 // 남아 있는 세마포 확인
   //  $ ipcrm -s <semid>     // <semid>라는 세마포 제거

   sleep(atoi(argv[1])); //argv[1] 초 후에 실행파일을 수행하기 위해 sleep

   int semid;
   pid_t pid;
   Lock lock;
   pid = getpid();
   initLock(&lock,semkey); //세마포 생성 (Lock)

   char* f_AR = "AR.txt"; //4개의 파일 생성 AR, WR, AW, WW (shared data)
   char* f_WR = "WR.txt";
   char* f_AW = "AW.txt";
   char* f_WW = "WW.txt";
   char* f_oTR = "okToRead.txt"; //2개의 파일 생성 Condition Read, Write
   char* f_oTW = "okToWrite.txt";

   int AR, WR, AW, WW; //4개의 카운터 생성
   
   CondVar okToRead; // 2개의 CondVar 생성 Read Condition, Write Condition
   CondVar okToWrite; 

   reset(f_AR); //shared data 초기화
   reset(f_WR);
   reset(f_AW);
   reset(f_WW);

   initCondVar(&okToRead, semRKey, f_oTR); //세마포 생성 (Read, Write)
   initCondVar(&okToWrite, semWKey, f_oTW);

   printf("\nprocess %d before critical section\n", pid);
   
   //first check self into system (Reader)

   Acquire(&lock);   // lock.Acquire()
   printf("process %d in critical section\n",pid);
   /* 화일에서 읽어서 1 더하기 */
   
   AW = Load(f_AW); //4개의 카운터에 텍스트 파일의 끝 값을 저장
   WW = Load(f_WW);
   AR = Load(f_AR);
   WR = Load(f_WR);

   while(AW + WW > 0) { //Active Writer 혹은 Waiting Writer가 존재할 경우 Reader를 Waiting 상태로 보냄 
    add(f_WR, 1); //재울때 add
    Wait(&okToRead, &lock);
    sub(f_WR, 1); //깰때 sub
    AW = Load(f_AW); //AW 와 WW를 while문 돌때마다 갱신
    WW = Load(f_WW);
   }

   add(f_AR, 1); //Active Reader의 수를 증가
   
   printf("process %d leaving critical section\n", pid);
   Release(&lock);   // lock.Release()

   sleep(atoi(argv[2])); //argv[2] 초만큼 읽는 시간을 수행

   //check out of system (Reader)

   Acquire(&lock);
   printf("process %d in critical section\n",pid);
   //조건문을 확인해 만족하면 okToWrtie에게 신호
   sub(f_AR, 1); //Active Reader의 수를 감소
   AR = Load(f_AR); //AR과 WW를 갱신
   WW = Load(f_WW);
   if(AR == 0 && WW > 0) { //마지막 Reader이고 기다리는 Writer가 있다면 신호
    Signal(&okToWrite);
   }
   Release(&lock);
   printf("process %d exiting\n",pid);
   exit(0);
}

This snippet took 0.01 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).