[t:/]$ 지식_

세마포어, 스핀락, 뮤텍스, 포직스 세마포어

2011/11/07

semaphore pthread posix semaphore mutex

대충 테스트 해보니..

스핀락 > 포직스 세마포어 > 뮤텍스 >>>>> 시스템 세마포어

  1. 시스템 세마포어는 IPC때만 쓰자.
  2. 스핀락이 빠르긴 하지만 블락 시간이 길면 망할 것 같음. (멀티코어에 어플 몇 개 안 떠 있으면 괜찮을 듯..)
  3. 포직스 세마포어가 뮤텍스 보다 복잡하긴 하지만 뮤텍스 보다 살짝 빠름. 바이너리 세마포어라면 걍 이게 갑인가?
  4. 뮤텍스가 간편하지만 하지만 내부 까보면 스핀락과 컴비네이션이 있을 것 같은데.. 뭐 나중에 뜯어보자.

뮤텍스, 스핀락, 세마포어는 전부 자원 돌려줘야 함;;
스레드 걍 냅두면 사라지겠지 하고 맨날 까먹는 것 중에 하나;

컨디셔널 밸류는 락 안에서 조건 체크하고 바로 락 풀면서 웨이팅 들어가고 싶을 때 씀.
물론 풀린 건 아니고 스핀하면서 웨이팅 하긴 싫을 때..

pthread_cond.. 아 대충 찾으면 나옴.

#include <stdio.h>
#include <pthread.h>
#include <sys/time.h> 
#include <sys/sem.h>
#include <semaphore.h>

void *count_func(void *param);    // 뮤텍스용 스레드 함수
void *count_func_spin(void *param); // 스핀락용 스레드 함수
void *count_func_posem(void *param);  // 포직스 세마포어용
void *count_func_sem(void *param);  // 시스템 세마포어용

unsigned int total_count = 589;   // 카운트 전역변수

pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER; // 뮤텍스 변수
pthread_spinlock_t count_spinlock;      // 스핀락 변수

int semid;  // 시스템 세마포어용 세마포어 아이디

// 시스템 세마포어용 공용체
union semun {
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
  struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                      (Linux-specific) */
};

// 포직스 세마포어용 변수
struct sembuf mysem_p  = {0, -1, SEM_UNDO}; // 세마포어 얻기 
struct sembuf mysem_v  = {0, 1, SEM_UNDO};  // 세마포어 돌려주기 

sem_t mysem; // 포직스 세마포어용 변수

// 현재 시간을 마이크로초로 돌려줌. 경과 시간을 잴 때 사용
static inline long myclock()
{
  struct timeval tv;
  
  gettimeofday (&tv, NULL);
  return (tv.tv_sec * 1000 * 1000 + tv.tv_usec);

}

// 뮤텍스 테스트
void test_case1(void)
{

  pthread_t count_thread[10];
        int result;
        int index;
        int thread_no[10];

        pthread_mutex_init(&count_lock, NULL);

        for (index = 0; index < 10; index++)
        {
                thread_no[index] = index;
                result = pthread_create(&(count_thread[index]), NULL, count_func, (void *)&(thread_no[index]));
                if (result < 0)
                {
                        perror("thread create error!\n");
                }
        }

  // 모든 스레드가 종료될 때 까지 기다림
  for (index = 0; index < 10; index++) 
    pthread_join(count_thread[index], NULL);

  // 뮤텍스 자원은 돌려주어야 함 
  pthread_mutex_destroy(&count_lock);
}

// 스핀락 테스트
void test_case2()
{
  
  pthread_t count_thread[10];
  int result;
        int index;
        int thread_no[10];

  pthread_spin_init(&count_spinlock, PTHREAD_PROCESS_PRIVATE);

        for (index = 0; index < 10; index++)
        {
                thread_no[index] = index;
                result = pthread_create(&(count_thread[index]), NULL, count_func_spin, (void *)&(thread_no[index]));
                if (result < 0)
                {
                        perror("thread create error!\n");
                }
        }

        for (index = 0; index < 10; index++)
                pthread_join(count_thread[index], NULL);
  
  
  pthread_spin_destroy(&count_spinlock);
  
}

// 포직스 세마포어 테스트
void test_case3()
{

        pthread_t count_thread[10];
        int result;
        int index;
        int thread_no[10];

  // 포직스 세마포어는 초기화 하고, 막고 풀면 땡임 
  if (sem_init(&mysem, 0, 1) == -1) 
  { 
          perror("Error");
    return; 
  } 

        for (index = 0; index < 10; index++)
        {
                thread_no[index] = index;
                result = pthread_create(&(count_thread[index]), NULL, count_func_posem, (void *)&(thread_no[index]));
                if (result < 0)
                {
                        perror("thread create error!\n");
                }
        }

        for (index = 0; index < 10; index++)
                pthread_join(count_thread[index], NULL);
  
  // 반드시 자원을 돌려줄 것.
  sem_destroy(&mysem);

}

// 시스템 세마포어 테스트
void test_case4()
{

  int sem_num = 1;
  union semun sem_union;  

        pthread_t count_thread[10];
        int result;
        int index;
        int thread_no[10];

        if (semid = semget(12345, sem_num, IPC_CREAT|0660) == -1)
        {
                perror("semget error\n");
                return -1;
        }

        sem_union.val = 1; 
        if ( -1 == semctl( semid, 0, SETVAL, sem_union)) 
        {    
                printf( "semctl()-SETVAL 실행 오류\n"); 
                return -1;  
        }   

        for (index = 0; index < 10; index++)
        {
                thread_no[index] = index;
                result = pthread_create(&(count_thread[index]), NULL, count_func_sem, (void *)&(thread_no[index]));
                if (result < 0)
                {
                        perror("thread create error!\n");
                }
        }

        for (index = 0; index < 10; index++)
                pthread_join(count_thread[index], NULL);

}

int main()
{

  long st, et;

  
  st = myclock();
  test_case1();
  et = myclock();
  printf("mutex test end!, total_count = %d, total_time = %ldus\n", total_count, et - st);
  
        st = myclock();
        test_case2();
        et = myclock();
        printf("spinlock test end!, total_count = %d, total_time = %ldus\n", total_count, et - st);

        st = myclock();
        test_case3();
        et = myclock();

        printf("posix semaphore test end!, total_count = %d, total_time = %ldus\n", total_count, et - st);

        st = myclock();
        test_case4();
        et = myclock();

        printf("system semaphore test end!, total_count = %d, total_time = %ldus\n", total_count, et - st);

  
}

void *count_func(void *param)
{
  int index;
  int thread_no = *(int *)param;

//  printf("I am thread %d\n", thread_no);

  for (index = 0; index < 100000; index++) {

    pthread_mutex_lock(&count_lock);
    total_count = total_count & 0x1 ? total_count + 1 : total_count - 1;
//    printf("total_count = %d, %d\n", total_count, thread_no);
    pthread_mutex_unlock(&count_lock);
//    usleep(rand() % 100000);
    
  }
  return NULL;
}

void *count_func_spin(void *param)
{
  int index;
  int thread_no = *(int *)param;

//        printf("I am thread spin %d\n", thread_no);

        for (index = 0; index < 100000; index++) {

                pthread_spin_lock(&count_spinlock);
    total_count = total_count & 0x1 ? total_count + 1 : total_count - 1;
//                printf("%d, total_count = %d, %d\n", index, total_count, thread_no);
                pthread_spin_unlock(&count_spinlock);
//              usleep(rand() % 100000);

        }

        return NULL;

}

void *count_func_posem(void *param)
{

        int index;
        int thread_no = *(int *)param;

        for (index = 0; index < 100000; index++) {

    sem_wait(&mysem);
          total_count = total_count & 0x1 ? total_count + 1 : total_count - 1;
    sem_post(&mysem);
 
  }

  return NULL;

}

void *count_func_sem(void *param)
{

        int index;
        int thread_no = *(int *)param;

        for (index = 0; index < 100000; index++) {

          if(semop(semid, &mysem_p, 1) == -1)
          {
                  perror("semop error ");
                  return NULL;
          }

          total_count = total_count & 0x1 ? total_count + 1 : total_count - 1;
 
          semop(semid, &mysem_v, 1);
  }

  return NULL;

}








[t:/] is not "technology - root". dawnsea, rss