본문 바로가기
Linux

[Linux] thread programming, mutex lock, semaphore in thread programming

by Bokoo14 2022. 12. 13.

# 13주차 1214 강의 요약

## Thread

프로세스: 서로 독립적인 메모리로 할당

쓰레드: 한 프로그램 내에서 독립적으로 실행하고 싶을 때 만들 수 있음

 

리눅스에서는 쓰레드 프로그램을 어떻게 하는가?

### p1.c

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

// 독립적으로 수행해야 하는 함수의 형식은 이런 형식이어야 한다 -> void * 형식이어야 한다 
void *func(void *arg){
    int i;
    for(i=0; i<5; i++){
        printf("It is working \n");
        sleep(1);
    }
}

void *func2(void *arg){
    int i;
    for(i=0; i<5; i++){
        printf("It is working2 \n");
        sleep(1);
    }
}
int main(){
    pthread_t thrd1, thrd2; // 쓰레드 아이디 생성
    int result, status;

    result = pthread_create(&thrd1, NULL, func, NULL); //쓰레드 생성
    result = pthread_create(&thrd2, NULL, func2, NULL); //쓰레드 생성

    for(int i=0; i<10; i++){
        printf("Main work .. \n");
        usleep(500000); //0.5초
    }

    pthread_join(thrd1, &status); //내가 만든 쓰레드가 끝나길 기다리고 결과를 status에 담아라 
    pthread_join(thrd2, &status); //thrd2가 끝나길 기다림.. 없으면? main이 먼저 끝나버리게 되면 하던 일을 다 못하고 프로그램이 종료됨
}

### bash shell

gcc p1.c -o p1 -lpthread

./p1

 

main함수와 fun함수가 동시에 실행됨

 

쓰레드를 생성하면 code, static, stack, heap영역을 모두 공유, stack영역만 쪼개서 씀 -> 쓰레드를 위한 스택을 별도로 잡아둠


### prime.c

하나의 쓰레드로 수행하면 n이 커지게 되면 시간이 매우 오래 걸림 .. -> multi thread가 필요!

// 소수의 개수를 구하는 알고리즘 -> n이 매우 커지면 시간이 오래 걸림
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

int isPrime(int n){
    for(int i=2; i<=n/2; i++){
        if (n%i==0){
            return 0;
        }
    }
    return 1;
}

int main(){
    int n;
    int count;

    printf("Enter a positive integer : ");
    scanf("%d", &n);
    count=0;
    //2~n까지 소수의 개수 구하기
    for(int i=2; i<=n; i++){
        if(isPrime(i)){
            count++;
        }
    }

    printf("The number of prime number is %d. \n", count);
}

### primethread.c

구간을 나눠서 두 개의 함수를 사용하여 두 개의 쓰레드로 실행. 독립적으로 수행

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

int isPrime(int n){
    for(int i=2; i<=n/2; i++){
        if (n%i==0){
            return 0;
        }
    }
    return 1;
}

int n;
// 쓰레드 함수는 형식이 정해져 있음
void *prime_count1(void *arg){
    int count=0;
    for(int i=2; i<=n/2; i++){
        if (isPrime(i)){count++;}
    }
    pthread_exit(count); //return 대신. 결과값(count)을 던져주면..
}
void *prime_count2(void *arg){
    int count=0;
    for(int i=n/2+1; i<=n; i++){
        if (isPrime(i)){count++;}
    }
    pthread_exit(count); //return 대신
}

int main(){
    int status;
    pthread_t thrd1, thrd2;
    
    printf("Enter a positive integer : ");
    scanf("%d", &n);

    pthread_create(&thrd1, NULL, prime_count1, NULL);
    pthread_create(&thrd2, NULL, prime_count2, NULL);

    pthread_join(thrd1, &status); // 함수에서 결과값을 던져주면 status에 결과값이 저장됨
    printf("status = %d \n", status);
    pthread_join(thrd2, &status);
    printf("status = %d \n", status);
}

### primethread2.c

함수 하나로 여러 개의 쓰레드 생성하여 실행

구조체를 생성해서 구간을 나눠서 실행

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

// 구조체 생성
struct PrimeTestRange{
    int startN;
    int endN;
};

int isPrime(int n){
    for(int i=2; i<=n/2; i++){
        if (n%i==0){
            return 0;
        }
    }
    return 1;
}

int n;
int total_count=0;
// 쓰레드 함수는 형식이 정해져 있음
//두 개 이상의 쓰레드가 동시에 읽고 써서 race condition이 발생할 수 있음!!
void *prime_count(void *arg){
    struct PrimeTestRange range;
    range = *(struct PrimeTestRange*)arg;

    for(int i=range.startN; i<=range.endN; i++){
        if (isPrime(i)){total_count++;}
    }
}

int main(){
    int status;
    pthread_t thrd1, thrd2;
    struct PrimeTestRange r1, r2;

    printf("Enter a positive integer : ");
    scanf("%d", &n);

    r1.startN=2;
    r1.endN=n/2;
    r2.startN=n/2+1;
    r2.endN=n;

    pthread_create(&thrd1, NULL, prime_count, &r1);
    pthread_create(&thrd2, NULL, prime_count, &r2);

    pthread_join(thrd1, &status); // 함수에서 결과값을 던져주면 status에 결과값이 저장됨
    pthread_join(thrd2, &status);
    printf("The number of prime numbers is %d \n", total_count);
}
오류 발생! 동시에 전역변수에 접근하게 되어 예상한 결과가 나오지 않음!! -> race condition
=> 이를 해결하기 위해 semaphore가 필요!!

 


## mutex lock

mutex lock: mutual exclusive lock

mutex lock을 사용한 multi thread

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

// 구조체 생성
struct PrimeTestRange{
    int startN;
    int endN;
};

int isPrime(int n){
    for(int i=2; i<=n/2; i++){
        if (n%i==0){
            return 0;
        }
    }
    return 1;
}

int n;
int total_count=0;
pthread_mutex_t count_lock;
// 쓰레드 함수는 형식이 정해져 있음
//두 개 이상의 쓰레드가 동시에 읽고 써서 race condition이 발생할 수 있음!! -> mutex lock이 필요
void *prime_count(void *arg){
    int count=0;
    struct PrimeTestRange range;
    range = *(struct PrimeTestRange*)arg;

    for(int i=range.startN; i<=range.endN; i++){
        if (isPrime(i)){
            count++; 
            }
    }
    pthread_mutex_lock (&count_lock); //lock-X
    total_count+=count;
    pthread_mutex_unlock(&count_lock); //unlock-x
}

int main(){
    int status;
    pthread_t thrd1, thrd2;
    struct PrimeTestRange r1, r2;

    printf("Enter a positive integer : ");
    scanf("%d", &n);

    r1.startN=2;
    r1.endN=n/2;
    r2.startN=n/2+1;
    r2.endN=n;

    pthread_create(&thrd1, NULL, prime_count, &r1);
    pthread_create(&thrd2, NULL, prime_count, &r2);

    pthread_join(thrd1, &status); // 함수에서 결과값을 던져주면 status에 결과값이 저장됨
    pthread_join(thrd2, &status);
    printf("The number of prime numbers is %d \n", total_count);
}

=> dead lock이 발생할 가능성이 있음!!

 

'Linux' 카테고리의 다른 글

[Linux] semaphore  (0) 2022.12.12
[Linux] message queue, shared memory  (0) 2022.12.12
[Linux] fork, pipe, mkfifo  (0) 2022.12.11
[Linux] programming shell, execvp, fork  (0) 2022.12.09