Creative Code

Chapter18(쓰레드,세마포어,mutex) 본문

TCP IP 소켓프로그래밍

Chapter18(쓰레드,세마포어,mutex)

빛하루 2023. 10. 11. 15:11

※thread1.c파일

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

void* thread_main(void *arg);

int main(int argc, char *argv[]) 
{
	pthread_t t_id;            // 쓰레드 식별자
	int thread_param = 5;      // 쓰레드에 전달할 인자

	if (pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0)
	{
		puts("pthread_create() error");
		return -1;
	}

	// 메인 쓰레드가 10초 동안 대기
	sleep(10);
	puts("end of main");
	return 0;
}

void* thread_main(void *arg) 
{
	int i;
	int cnt = *((int*)arg);   // 쓰레드에 전달된 인자를 정수로 변환

	// 주어진 횟수만큼 반복하면서 "running thread"를 출력하고 1초 대기
	for (i = 0; i < cnt; i++)
	{
		sleep(1);
		puts("running thread");
	}

	return NULL;
}

※thread2.c파일

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

void* thread_main(void *arg);

int main(int argc, char *argv[]) 
{
	pthread_t t_id;
	int thread_param = 5;
	void *thr_ret;  // 쓰레드의 반환 값을 저장하기 위한 포인터

	// 쓰레드 생성
	if (pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0)
	{
		puts("pthread_create() error");
		return -1;
	}

	// 쓰레드가 종료될 때까지 대기하고 반환 값을 받음
	if (pthread_join(t_id, &thr_ret) != 0)
	{
		puts("pthread_join() error");
		return -1;
	}

	// 쓰레드의 반환 값을 출력
	printf("Thread return message: %s\n", (char*)thr_ret);
	free(thr_ret);  // 동적으로 할당한 메모리를 해제
	return 0;
}

void* thread_main(void *arg) 
{
	int i;
	int cnt = *((int*)arg);
	char *msg = (char*)malloc(sizeof(char) * 50);
	strcpy(msg, "Hello, I'm thread~\n");  // 메시지를 할당하고 복사

	for (i = 0; i < cnt; i++)
	{
		sleep(1);
		puts("running thread");
	}

	// 쓰레드의 반환 값으로 메시지를 반환 (메인 쓰레드에서 해제해야 함)
	return (void*)msg;
}

※thread3.c파일

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

// 전역 변수로 합을 저장할 변수 선언
int sum = 0;

// 쓰레드 함수 원형 선언
void* thread_summation(void* arg);

int main(int argc, char* argv[])
{
    pthread_t id_t1, id_t2;
    int range1[] = {1, 5};
    int range2[] = {6, 10};
    
    // 첫 번째 쓰레드 생성 및 실행
    pthread_create(&id_t1, NULL, thread_summation, (void*)range1);
    
    // 두 번째 쓰레드 생성 및 실행
    pthread_create(&id_t2, NULL, thread_summation, (void*)range2);

    // 두 쓰레드의 실행이 완료될 때까지 대기
    pthread_join(id_t1, NULL);
    pthread_join(id_t2, NULL);

    // 결과 출력
    printf("result: %d\n", sum);

    return 0;
}

// 쓰레드 함수 정의
void* thread_summation(void* arg) 
{
    int start = ((int*)arg)[0];
    int end = ((int*)arg)[1];

    while (start <= end)
    {
        sum += start;
        start++;
    }

    return NULL;
}

※thread4.c파일

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

#define NUM_THREAD 100

// 두 가지 타입의 쓰레드 함수 원형 선언
void *thread_inc(void *arg);
void *thread_des(void *arg);

// 전역 변수로 사용할 long long 타입의 변수 선언
long long num = 0;

// 쓰레드 동기화를 위한 mutex 선언
pthread_mutex_t mutex;

int main(int argc, char *argv[]) 
{
    pthread_t thread_id[NUM_THREAD];
    int i;

    // mutex 초기화
    pthread_mutex_init(&mutex, NULL);

    printf("sizeof long long: %d\n", sizeof(long long));

    // NUM_THREAD 수만큼의 쓰레드를 생성하고 실행
    for (i = 0; i < NUM_THREAD; i++)
    {
        if (i % 2) {
            // 홀수 인덱스의 쓰레드는 "thread_inc" 함수 실행
            pthread_create(&(thread_id[i]), NULL, thread_inc, NULL);
        }
        else {
            // 짝수 인덱스의 쓰레드는 "thread_des" 함수 실행
            pthread_create(&(thread_id[i]), NULL, thread_des, NULL);
        }
    }

    // 모든 쓰레드의 실행이 완료될 때까지 대기
    for (i = 0; i < NUM_THREAD; i++) {
        pthread_join(thread_id[i], NULL);
    }

    // 결과 출력
    printf("result: %lld\n", num);

    // mutex 해제
    pthread_mutex_destroy(&mutex);
    return 0;
}

// "thread_inc" 함수 정의: num을 증가시키는 함수
void *thread_inc(void *arg) 
{
    int i;

    // mutex를 사용하여 동기화
    pthread_mutex_lock(&mutex);

    for (i = 0; i < 50000000; i++) {
        num += 1;
    }

    // mutex 해제
    pthread_mutex_unlock(&mutex);

    return NULL;
}

// "thread_des" 함수 정의: num을 감소시키는 함수
void *thread_des(void *arg)
{
    int i;

    // mutex를 사용하여 동기화
    pthread_mutex_lock(&mutex);

    for (i = 0; i < 50000000; i++) {
        num -= 1;
    }

    // mutex 해제
    pthread_mutex_unlock(&mutex);

    return NULL;
}

※semaphore.c파일

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

void * read(void * arg);
void * accu(void * arg);
static sem_t sem_one;
static sem_t sem_two;
static int num;

int main(int argc, char *argv[])
{
	pthread_t id_t1, id_t2;
	sem_init(&sem_one, 0 /*기본 값*/, 0 /*생성되는 세마포어의 초기 값*/);
	sem_init(&sem_two, 0 /*기본 값*/, 1 /*생성되는 세마포어의 초기 값*/);

	pthread_create(&id_t1, NULL, read, NULL);
	pthread_create(&id_t2, NULL, accu, NULL);

	pthread_join(id_t1, NULL);
	pthread_join(id_t2, NULL);

	sem_destroy(&sem_one);
	sem_destroy(&sem_two);
	return 0;
}

void * read(void * arg)
{
	int i;
	for(i=0; i<5; i++)
	{
		fputs("Input num: ", stdout);

		// -(빼기) 
		sem_wait(&sem_two);
		
		scanf("%d", &num);
		
		// +(더하기)
		sem_post(&sem_one);
	}
	return NULL;	
}
void * accu(void * arg)
{
	int sum=0, i;
	for(i=0; i<5; i++)
	{
		sem_wait(&sem_one);
		sum+=num;
		sem_post(&sem_two);
	}
	printf("Result: %d \n", sum);
	return NULL;
}

※thread5.c파일

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

void* thread_main1(void *arg);
void* thread_main2(void *arg);
void* thread_main3(void *arg);

// 세 개의 세마포어를 선언
static sem_t sem_one;
static sem_t sem_two;
static sem_t sem_thr;

int main(int argc, char *argv[]) 
{
	pthread_t t1_id, t2_id, t3_id;
	int thread_param = 5;

    // 세마포어 초기화
    sem_init(&sem_one, 0, 0);  // 초기 값 0
	sem_init(&sem_two, 0, 0);  // 초기 값 0
    sem_init(&sem_thr, 0, 1);  // 초기 값 1

	pthread_create(&t1_id, NULL, thread_main1, (void*)&thread_param);
    pthread_create(&t2_id, NULL, thread_main2, (void*)&thread_param);
    pthread_create(&t3_id, NULL, thread_main3, (void*)&thread_param);

	pthread_join(t1_id, NULL);
    pthread_join(t2_id, NULL);
    pthread_join(t3_id, NULL);

    // 세마포어 해제
    sem_destroy(&sem_one);
	sem_destroy(&sem_two);
    sem_destroy(&sem_thr);

	sleep(1);
  	puts("end of main");
	return 0;
}

void* thread_main1(void *arg) 
{
	int i;
	int cnt = *((int*)arg);
	for (i = 0; i < cnt; i++)
	{
        sleep(1);  
        sem_wait(&sem_one);  // sem_one 세마포어 대기
		puts("running thread1");
        sem_post(&sem_thr);  // sem_thr 세마포어 해제
	}
	return NULL;
}

void* thread_main2(void *arg) 
{
	int i;
	int cnt = *((int*)arg);
	for (i = 0; i < cnt; i++)
	{
        sleep(1);  
        sem_wait(&sem_two);  // sem_two 세마포어 대기
		puts("running thread2");	
        sem_post(&sem_one);  // sem_one 세마포어 해제
	}
	return NULL;
}

void* thread_main3(void *arg) 
{
	int i;
	int cnt = *((int*)arg);
	for (i = 0; i < cnt; i++)
	{
        sleep(1);  
        sem_wait(&sem_thr);  // sem_thr 세마포어 대기
		puts("running thread3");
        sem_post(&sem_two);  // sem_two 세마포어 해제
	}
	return NULL;
}

※echo_server.c파일

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

#define BUF_SIZE 1024
#define NUM_THREAD 5

void error_handling(char *message);
void* thread_main(void* arg);

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	char message[BUF_SIZE];
	int str_len, i;
	pthread_t thread_id[NUM_THREAD];

	struct sockaddr_in serv_adr;
	struct sockaddr_in clnt_adr;
	socklen_t clnt_adr_sz;
	
	if(argc!=2) {
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
	
	serv_sock=socket(PF_INET, SOCK_STREAM, 0);   
	if(serv_sock==-1)
		error_handling("socket() error");
	
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family=AF_INET;
	serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_adr.sin_port=htons(atoi(argv[1]));

	if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
		error_handling("bind() error");
	
	if(listen(serv_sock, 5)==-1)
		error_handling("listen() error");
	
	clnt_adr_sz=sizeof(clnt_adr);

	for(i=0; i<5; i++)
	{
		clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
		if(clnt_sock==-1)
			error_handling("accept() error");
		else
			printf("Connected client %d \n", i+1);

        // 새로운 쓰레드를 생성하고 클라이언트 소켓을 인자로 전달
        pthread_create(&thread_id[i], NULL, thread_main, (void*)&clnt_sock);
        // 쓰레드를 백그라운드에서 실행 (non-blocking)
        pthread_detach(thread_id[i]);
	}

	close(serv_sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

void* thread_main(void* arg) {
    int str_len;
    int clnt = *((int*)arg);
    char message[BUF_SIZE];
    while((str_len=read(clnt, message, BUF_SIZE))!=0)
			write(clnt, message, str_len);
    return NULL;
}