semaphore pthread posix semaphore mutex
대충 테스트 해보니..
스핀락 > 포직스 세마포어 > 뮤텍스 >>>>> 시스템 세마포어
뮤텍스, 스핀락, 세마포어는 전부 자원 돌려줘야 함;;
스레드 걍 냅두면 사라지겠지 하고 맨날 까먹는 것 중에 하나;
컨디셔널 밸류는 락 안에서 조건 체크하고 바로 락 풀면서 웨이팅 들어가고 싶을 때 씀.
물론 풀린 건 아니고 스핀하면서 웨이팅 하긴 싫을 때..
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;
}