세마포어 값을 변경 semop()

2020. 3. 16. 09:44 컴퓨터/프로그래밍

C함수 세마포어 값을 변경 semop()

semop() 함수는 세마포어의 값을 변경합니다. 세마포어를 사용하기 위해서는 먼저 세마포어 값을 1 감소시키고, 사용 후에는 1 증가시키는데, 이렇게 세마포어값을 증감하는 것을 요청하는 함수입니다.

  • 헤더: sys/types.h, sys/ipc.h, sys/sem.h
  • 형태: int semop ( int semid, struct sembuf *sops, unsigned nsops )
  • 인수: int semid 시스템에서 세머포어를 식별하는 집합 번호
    struct sembuf *sops 세마포어 값을 계사하기위한 설정 값
    unsigned nsops 변경하려는 세마포어 개수로 변경하려는 세마포어 개수가 여러 개일 때 사용합니다.
  • 반환: 0 == 성공, -1 == 실패

struct sembuf *sops 세마포어 값을 계사하기위한 설정 값

struct sembuf {
    short sem_num;   세마포어 번호
    short sem_op;     세마포어 증감값
    short sem_flg;     옵션 
}
struct sembuf *sops 세마포어 값을 계사하기위한 설정 값

sem_flg 내용
IPC_NOWAIT 호출 즉시 실행하지 못했을 경우 기다리지 않고 실패로 바로 복귀합니다.
SEM_UNDO 프로세스가 종료되면 시스템에서 세마포어 설저을 원래 상태로 되돌립니다. 그러므로 보통 이 옵션을 사용합니다.
unsigned nsops 변경하려는 세마포어 개수로 변경하려는 세마포어 개수가 여러 개일 때 사용합니다. 예를 들어 변경하려는 세마포어 개수가 한 개라면
struct sembuf sbuf = { 0, -1, 0}; 
semop( semmop, &sbuf, 1);

이렇게 값이 1이 되지만 한번에 2개 이상의 세마포어를 변경한다면,

struct sembuf pbuf[2]   = {
      { 0,  1, 0} ,   // 첫번째 세마포어 값을 1 증가 
      { 1, -1, 0}     // 두번째 세마포어 값을 1 감소 
    } 
semop( semmop, pbuf, 2);

예제

예제에서는 두개의 쓰레드를 만들어 첫번째 쓰레드는 카운터 값을 증가 시키고 두번째 쓰레드는 카운터를 화면에 출력합니다. 카운터가 5 이상의 값이 되면 두 개의 쓰레드는 모두 종료하고 프로그램이 종료되면서 세마포어를 삭제합니다.

#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int         cnt   = 0;
static int  semid;

void p()
{
   struct sembuf pbuf;

   pbuf.sem_num   = 0;
   pbuf.sem_op    = -1;
   pbuf.sem_flg   = SEM_UNDO;

   if ( -1 == semop(semid, &pbuf, 1))
      printf( "p()-semop() 실행 오류\n");
}

void v()
{
   struct sembuf vbuf;

   vbuf.sem_num   = 0;
   vbuf.sem_op    = 1;
   vbuf.sem_flg   = SEM_UNDO;

   if ( -1 == semop( semid, &vbuf, 1))
      printf( "v()-semop() 실행 오류\n");
}
void *fun_thread1(void *arg)
{
   while( 1){
      p();
      printf( "thread1 실행\n");
      if ( 5 < cnt){
         printf( "thread1 완전 종료\n");
         v();
         break;
      } else {
         cnt++;
         usleep( 100);
         printf( "thread1 완료\n");
      }
      v();
   }
   return NULL;
}
void *fun_thread2(void *arg)
{
   while( 1){
      p();
      printf( "thread2 실행\n");
      if ( 5 < cnt){
         printf( "thread2 완전 종료\n");
         v();
         break;
      } else {
         printf( "카운터= %d\n", cnt);
         usleep( 100);
         printf( "thread2 완료\n");
      }
      v();
   }
   return NULL;
}
int main(int argc, char *argv[])
{
   pthread_t thread1;
   pthread_t thread2;

   union semun{
      int                  val;
      struct   semid_ds   *buf;
      unsigned short int  *arrary;
   }  arg;

   if ( -1 == (semid = semget( IPC_PRIVATE, 1, IPC_CREAT ¦ 0666))){
      printf( "semget() 실행 오류\n");
      return -1;
   }
   arg.val  =  1;                // 세마포어 값을 1로 설정
   if ( -1 == semctl(semid, 0, SETVAL, arg)){
      printf( "semctl()-SETVAL 실행 오류\n");
      return -1;
   }
   pthread_create(&thread1, NULL, fun_thread1, NULL);
   pthread_create(&thread2, NULL, fun_thread2, NULL);
   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);

   if ( -1 == semctl(semid, 0, IPC_RMID, arg)){
      printf( "semctl()-IPC_RMID 실행 오류\n");
      return -1;
   }
   printf( "프로그램 종료\n");
   return 0;
}

실행 결과

]  gcc test.c -lpthread
]$ ./a.out
thread2 실행
카운터= 0
thread2 완료
thread1 실행
thread1 완료
thread2 실행
카운터= 1
thread2 완료
thread1 실행
thread1 완료
thread2 실행
카운터= 2
thread2 완료
thread1 실행
thread1 완료
thread2 실행
카운터= 3
thread2 완료
thread1 실행
thread1 완료
thread2 실행
카운터= 4
thread2 완료
thread1 실행
thread1 완료
thread2 실행
카운터= 5
thread2 완료
thread1 실행
thread1 완료
thread2 실행
thread2 완전 종료
thread1 실행
thread1 완전 종료
프로그램 종료
]$
이 댓글을 비밀 댓글로