본문 바로가기

컴퓨터 과학/리눅스 프로그래밍

[이론] 스레드(Thread)와 뮤텍스 스레드(Mutex Thread)

반응형

정의

스레드(Thread) : 프로세스 내에서 실행되는 흐름의 단위를 말한다. 모든 프로그램은 하나 이상의 스레드를 가진다.

멀티 프로세스와 다르게 멀티 스레드는 스레드 간 프로세스 내 메모리를 공유할 수 있다는 장점이 있다.

    => 별도의 IPC가 필요없어서 더 빠르고, 더 간단하다. 

단, 여러 스레드 중 어느 스레드가 실행되는 지 알 수 없어서, 스레드 간 동기화가 필요하다. 이를 위한 스레드가 뮤텍스 스레드(Mutex Thread)이다. 뮤텍스 스레드는 임계 영역을 설정하여, 해당 영역에서는 context 스위칭이 일어나지 않도록 방지하는 기능을 포함한다.

 

스레드 구성

스레드의 종류

  • User-Level Thread : 커널 영역 상위 레벨에서 지원되며, 일반 라이브러리로 스레드 생성 및 관리, 동일한 메모리 영역에서 스레드가 관리되므로 속도가 빠르나, 여러 개의 스레드 중 하나의 스레드가 시스템 콜에 종료되면 다른 스레드도 종료된다는 단점이 있다.
  • Kernel-Level Thread : 운영체제가 지원하는 스레드 기능, 커널에 의해 스레드가 생성 및 관리된다. 시스템 호출 등으로 하나의 스레드가 중단되더라도, 나머지 스레드는 독립적으로 운영된다. 다만 User-Level Thread에 비해서 속도가 느리다.

일반 스레드 사용 예시

#include <stdio.h> 		/* printf() 함수를 위한 헤더 파일 */
#include <unistd.h>
#include <fcntl.h> 		/* O_CREAT, O_EXEC 매크로를 위한 헤더 파일 */
#include <pthread.h>
#include <semaphore.h> 		/* sem_open(), sem_destroy(), sem_wait() 등 함수를 위한 헤더 파일 */

sem_t *sem; 			/* 세마포어를 위한 전역 변수 */
static int cnt = 0; 		/* 세마포어에서 사용할 임계 구역 변수 */

void p() 			/* 세마포어의 P 연산 */
{
    sem_post(sem);
}

void v() 			/* 세마포어의 V 연산 */
{
    sem_wait(sem);
}

void *ptheadV(void *arg) 	/* V 연산을 수행하기 위한 함수를 작성한다. */
{
    int i;

    for(i = 0; i < 10; i++) {
        if(cnt >= 7) usleep(100); 	/* 7 이상이면 100밀리초 동안 대기한다. */
        cnt++;
        printf("increase : %d\n", cnt) ;
        fflush(NULL);
        v();
    }

    return NULL;
}

void *ptheadP(void *arg) 	/* P 연산을 수행하기 위한 함수를 작성한다. */
{
    int i;

    for(i = 0; i < 10; i++) {
        p(); 			/* 세마포어가 0이 되면 블록된다. */
        cnt--;
        printf("decrease : %d\n", cnt);
        fflush(NULL);
        usleep(100); 		/* 100밀리초 간 기다린다. */
    }

    return NULL;
}

int main(int argc, char **argv)
{
    pthread_t ptV, ptP; 	/* 스레드를 위한 자료형 */
    const char* name = "posix_sem";
    unsigned int value = 7; 	/* 세마포어의 값 */

    /* 세마포어 열기 */
    sem = sem_open(name, O_CREAT, S_IRUSR | S_IWUSR, value);
    pthread_create(&ptV, NULL, ptheadV, NULL); 	/* 스레드 생성 */
    pthread_create(&ptP, NULL, ptheadP, NULL);

    pthread_join(ptV, NULL); 	/* 스레드가 종료될 때까지 대기 */
    pthread_join(ptP, NULL);

    /* 다 쓴 세마포어 닫고 정리 */
    sem_close(sem);
    printf("sem_destroy() : %d\n", sem_destroy(sem));

    /* 세마포어 삭제 */
    sem_unlink(name);

    return 0;
}

 

뮤텍스 스레드 사용 예시

#include <stdio.h>
#include <pthread.h>

int g_var = 1;
pthread_mutex_t mid;

void *inc_function(void *);
void *dec_function(void *);

int main(int argc, char **argv)
{
    pthread_t ptInc, ptDec;

    pthread_mutex_init(&mid, NULL); 	/* 뮤텍스 초기화 */

    pthread_create(&ptInc, NULL, inc_function, NULL);

    pthread_create(&ptDec, NULL, dec_function, NULL);
    pthread_join(ptInc, NULL);
    pthread_join(ptDec, NULL);

    pthread_mutex_destroy(&mid); 	/* 뮤텍스 삭제 */

    return 0;
}

void *inc_function(void *arg)
{
    pthread_mutex_lock(&mid); 		/* 임계 구역 설정 */
    printf("Inc : %d < Before\n", g_var);
    g_var++;
    printf("Inc : %d > After\n", g_var);
    pthread_mutex_unlock(&mid); 	/* 임계 구역 해제 */

    return NULL;
}

void *dec_function(void *arg)
{
    pthread_mutex_lock(&mid); 		/* 임계 구역 설정 */
    printf("Dec : %d < Before\n", g_var);
    g_var--;
    printf("Dec : %d > After\n", g_var);
    pthread_mutex_unlock(&mid); 	/* 임계 구역 해제 */

    return NULL;
}

 

코드 출처 : https://github.com/valentis/LinuxProgrammingWithRaspberryPi/tree/master/Chapter5

 

LinuxProgrammingWithRaspberryPi/Chapter5 at master · valentis/LinuxProgrammingWithRaspberryPi

Linux Programming With Raspberry Pi. Contribute to valentis/LinuxProgrammingWithRaspberryPi development by creating an account on GitHub.

github.com

thread.c, thread_mutex.c

반응형