본문 바로가기

42cursus

philosophers[철학자] - 외부함수 정리하기 (시간, 쓰레드, 뮤텍스, 세마포어)

=== 시간 함수 ===

int usleep(useconds_t microseconds)

마이크로초 만큼 쓰레드 대기

헤더

 - unistd.h

파라미터

 - microseconds: 1 / 1000 * 1000 초

반환

 - 성공 시: 0 반환

 - 실패 시: -1 반환

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <unistd.h>
int        main(void)
{
    int i = 0;
    while (i < 3)
    {
        usleep(1000 * 1000);
        i++;
        printf("%d초 째 대기 중\n", i);
    }
    return (0);
}
cs

 

 

int gettimeofday(struct timeval *tp, void *tzp)

현재 시간을 마이크로단위로 얻을 수 있음

반환으로 얻는 것이 아닌 레퍼런스로 얻음

헤더

 - sys/time.h

파라미터

 - time_ptr: 현재 시스테메 시간을 저장하기 위한 구조체 포인터

 - timezone_ptr: 사용되지 않음

반환

 - 성공 시: 0 반환

 - 실패 시 : -1 반환

cf)

struct timeval {

    long tv_sec;    // 초

    int tv_usec;  // 마이크로초

}

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <sys/time.h>
int        main(void)
{
    struct timeval    my_time;
    gettimeofday(&my_time, NULL);
    printf("time : %ld\n", my_time.tv_sec);
    printf("macro time : %d\n", my_time.tv_usec);
    return (0);
}
cs

 

 

 

 

 

=== 쓰레드 함수 ===

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)

새로운 쓰레드를 생섬함

헤더

 - pthread.h

파라미터

 - thread: 쓰레드 식별값 (고유 아이디)

 - attr: pthread옵션 (옵션을 사용하지 않으면 NULL)

 - start_routine: 쓰레드 함수 (루틴 함수)

 - arg: 쓰레드 함수에서 사용할 인자 (void*형이지만 쓰레드 함수에서 캐스팅하여 사용)

반환

 - 성공 시: 0 반환

 - 실패 시: 에러 넘버

 

 

int pthread_detach(pthread_t thread)

부모 쓰레드로부터 분리 -> 부모쓰레드가 해당 쓰레드를 기다리지 않음

독립된 thread는 종료시 자동으로 리소스 해제

헤더

 - pthread.h

파라미터

 - thread: 쓰레드 식별값 (고유 아이디)

반환

 - 성공 시: 0 반환

 - 실패 시: 에러 넘버

 

 

int pthread_join(pthread_t thread, void **value_ptr)

특정 thread가 종료될 때까지 기다리다가, 그 thread가 종료되면 리소스를 해제시킴

이미 종료된 thread면 기다리지 않음

헤더

 - pthread.h

파라미터

 - thread: 쓰레드 식별값 (고유 아이디)

 - value_ptr: pthread_create의 쓰레드 함수(start_routine)의 반환값을 받음

반환

 - 성공 시: 0 반환

 - 실패 시: 에러 넘버

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
 
void    *routine(void *thread_number)
{
    int        i;
    int        cnt;
 
    i = 0;
    while (i < 5)
    {
        usleep(1000 * 1000);
        i++;
        printf("thread(%d): %d초 대기\n"*(int *)thread_number, i);
    }
    printf("thread end\n");
    return (thread_number);
}
 
int        main(void)
{
    pthread_t    thread1;
    pthread_t    thread2;
    int            number1;
    int            number2;
    void        *ret;
 
    number1 = 1;
    number2 = 2;
    if (pthread_create(&thread1, NULL, routine, (void *)&number1))
    {
        fprintf(stderr, "thread(1): pthread_create error: %s", strerror(errno));
        return (errno);
    }
    if (pthread_create(&thread2, NULL, routine, (void *)&number2))
    {
        fprintf(stderr, "thread(2): pthread_create error: %s", strerror(errno));
        return (errno);
    }
    printf("detach thread2\n");
    pthread_detach(thread2); // main thread에서 join하지 않아도 알아서 진행하고 종료함
    printf("waiting for a thread\n");
    pthread_join(thread1, &ret); // thread1을 대기함, routine의 값을 ret에 넣어줌
    printf("main end: %d\n"*(int *)ret);
    return (0);
}
 
cs

 

 

 

 

 

=== 뮤텍스 함수 ===

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)

새로운 뮤텍스를 생성함

헤더

 - pthread.h

파라미터

 - mutex: 초기화 받을 mutex객체

 - attr: 초기화 할 때 뮤텍스의 특징을 정의할 수 있는 속성 (기본으로 사용하려면 NULL)

반환

 - 성공 시: 0 반환

 - 실패 시: 에러 넘버

 

 

int pthread_mutex_destroy(pthread_mutex_t *mutex)

뮤텍스가 할당받은 리소스를 해제시킴

헤더

 - pthread.h

파라미터

 - mutex: free시킬 뮤텍스

반환

 - 성공 시: 0 반환

 - 실패 시: 에러 넘버

 

 

int pthread_mutex_lock(pthread_mutex_t *mutex)

기본적으로는 뮤텍스를 lock시킴

이미 뮤텍스가 lock인 상태이면 block상태로 들어가서 mutex를 사용할 수 있을 때 까지 대기함

헤더

 - pthread.h

파라미터

 - mutex: lock시킬 뮤텍스

반환

 - 성공 시: 0

 - 실패 시: 에러 넘버

 

 

int pthread_mutex_unlock(pthread_mutex_t *mutex)

현재 쓰레드가 뮤텍스를 잡고 있으면 unlock시킴

자신이 홀드하고 있는 뮤텍스가 아닌 것을 unlock시키면 undefined

헤더

- pthread.h

파라미터

 - mutex: unlock시킬 뮤텍스

반환

 - 성공 시: 0

 - 실패 시: 에러 넘버

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
 
pthread_mutex_t    mutex;
 
void    *routine(void *thread_number)
{
    int        i;
    int        cnt;
 
    pthread_mutex_lock(&mutex);
    printf("thread(%d): mutex lock\n"*(int *)thread_number);
    i = 0;
    while (i < 5)
    {
        usleep(1000 * 1000);
        i++;
        printf("thread(%d): %d초 대기\n"*(int *)thread_number, i);
    }
    printf("thread end\n");
    pthread_mutex_unlock(&mutex);
    printf("thread(%d): mutex unlock\n"*(int *)thread_number);
    return (thread_number);
}
 
int        main(void)
{
    pthread_t    thread1;
    pthread_t    thread2;
    int            number1;
    int            number2;
    void        *ret;
 
    number1 = 1;
    number2 = 2;
    printf("pthread create\n");
    pthread_create(&thread1, NULL, routine, (void *)&number1);
    pthread_create(&thread2, NULL, routine, (void *)&number2);
 
    printf("mutex init\n");
    pthread_mutex_init(&mutex, NULL);
 
    printf("waiting for threads\n");
    pthread_join(thread1, &ret); // thread1을 대기함, routine의 값을 ret에 넣어줌
    pthread_join(thread1, &ret); // thread1을 대기함, routine의 값을 ret에 넣어줌
 
    printf("mutex destroy\n");
    pthread_mutex_destroy(&mutex);
 
    printf("main end\n");
    return (0);
}
 
cs

출력이 겹치지 않음

 

 

 

 

 

=== 세마포어 함수 ===

sem_t *sem_open(const char *name, int oflag, [mode], [value])

named semaphore 생성

헤더

 - semaphore.h

파라미터

 - name: 생성 또는 접근하고자 하는 세마포어 이름

 - oflag: O_CREATE와 O_EXCL의 조합

 - mode: 허가권, open()와 동일

 - value: 세마포어의 수 (초기값)

반환

 - 성공 시: 세마포어 디스크립터

 - 실패 시: SEM_FAILED

cf) oflag

 -> O_CREAT: create the semaphore if it does not exist

 -> O_EXCL: error if create and semaphore exists

 

 

int sem_close(sem_t *sem)

세마포어 사용종료

세마포어를 사용 하도록 시스템이 할당한 자원들을 모두 해제

헤더

 - semaphore.h

파라미터

 - sem: 해제시킬 sem포인터

반환

 - 성공 시: 0

 - 실패 시: - 1

 

 

int sem_post(sem_t *sem)

세마포어를 unlock

세마포어의 value값이 1 증가

해당 세마포어를 대기중인 스레드는 깨어남

헤더

 - semaphore.h

파라미터

 - sem: unlock할 세마포어

반환

 - 성공 시: 0

 - 실패 시: -1

 

 

int sem_wait(sem_t *sem)

세마포어를 lock

세마포어의 value값이 1 감소

만약 세마포어의 value값이 0이라면 wait호출자는 block상태 (대기)

헤더

 - semaphore.h

파라미터

 - sem: lock할 세마포어

반환

 - 성공 시: 0

 - 실패 시: -1

 

 

int sem_unlink(const char *name)

name인 이름을 가진 세마포어를 "제거"

프로세스가 참조하고 있다면 unlink되지 않는다고 함

헤더

 - semaphore.h

파라미터

 - name: 제거해야할 세마포어name

반환

 - 성공 시: 0

 - 실패 시: -1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
 
sem_t        *sem;
 
void    *routine(void *num)
{
    sem_wait(sem);
    for (int i = 0; i < 3++i)
    {
        printf("%d: use semaphore\n"*(int *)num);
        usleep(1000 * 1000);
    }
    sem_post(sem);
    return (num);
}
 
int        main(void)
{
    int            ret;
    pthread_t    tid[4];
    int            num[4];
 
    sem = sem_open("test_sem", O_CREAT | O_EXCL, 06443);
    if (sem == SEM_FAILED)
    {
        fprintf(stderr, "sem error\n");
        return (-1);
    }
 
    for (int i = 0; i < 4++i)
    {
        num[i] = i;
        pthread_create(&tid[i], NULL, routine, (void *)&num[i]);
    }
    for (int i = 0; i < 4++i)
        pthread_join(tid[i], NULL);
    ret = sem_close(sem);
    printf("sem_close: %d\n", ret);
    ret = sem_unlink("test_sem");
    printf("sem_unlink: %d\n", ret);
    return (0);
}
cs

3이 세마포어를 가장 늦게 잡는 모습

 

프로세스와 세마포어 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/wait.h>
 
int        main(void)
{
    pid_t    pid;
    int        num;
    int        status;
    sem_t    *sem;
 
    sem_unlink("test_sem");
    sem = sem_open("test_sem", O_CREAT | O_EXCL, 06441);
    for (int i = 0; i < 4++i)
    {
        pid = fork();
        num = i;
        if (pid == 0)
            break ;
    }
    if (pid == 0/* child */
    {
        sem_wait(sem);
        for (int i = 0; i < 3; i++)
        {
            printf("%d\tcritical sections\n", num);
            sleep(1);
        }
        sem_post(sem);
    }
    else /* parent */
    {
        while (wait(&status) > 0);
        printf("child ended\n");
    }
    return (0);
}
cs