본문 바로가기
코딩/C 언어

C언어 기초 - 쓰레드 이해하고 사용하는 방법

by DIYver 2020. 7. 9.

본문 목표

코드를 여러개 동시에 돌리고 싶을 때, 사용하는 것이 쓰레드이다.

 

쓰레드의 원리를 이해하고, 사용방법을 알아보자.

 

 

 

 

 

 

개념 정리

코드는 하나만 돌아가는 것이 기본이다.

 

그런데 성능 좋은 컴퓨터에서 여러개를 동시에 처리하지 못하는 것 만큼 제값 못하는건 또 없다.

 

여러개를 동시에 처리하기 위한 개념이 쓰레드이다.

 

다시말해서 코드는 하나 실행했는데, 작동되는 기능이 2개 이상 되게 하는 것이 쓰레드이다.

 

 

아두이노 같은 임베디드 보드를 사용하면

 

우리는 loop( ) 또는 while(1) 처럼 무한 반복문 안에다가 코딩을 하고,

 

계속 반복을 돌리게 한다.

 

그런데 기능을 두가지를 동시에 하게 하고 싶으면

 

timer 기능을 사용하게 된다.

 

예를 들어, 타이머를 시작해두고, 100ms 마다

 

1번 기능의 while( ) 을 작동시키고, 2번 기능의 while( ) 을 작동시키면 

 

동시에 구현되는 것처럼 보이게 할 수 있다.

 

 

하지만 한계가 있다.

 

실행하려는 코드가 복잡한 경우 제때 복귀하지 못하면 제대로 실행이 되지 않는 것이다.

 

다시 말해서 간단한 경우에나 동시에 작동하는 것처럼 보이게 할 수 있는 것이다.

 

 

 

 

timer 기능을 사용하지 않는다면, 인터럽트 개념을 사용해야 된다.

 

timer 인터럽트를 사용해서 메인 함수는 메인 함수대로 작동하고, 일정 시간마다 다른 코드를 실행시키게 하는 것이다.

 

 

이 역시도 완벽한 것은 아니다.

 

타이머 인터럽트에서 시간을 많이 뺏게되면 메인 함수가 제대로 실행되지 않게 된다.

 

 

 

쓰레드 개념을 사용하면 동시에 돌리려는 코드가 완벽하게 작동되게 할 수 있다.

 

이는 os를 갖는 컴퓨터에서 사용가능하고, 임베디드 보드에서는 사용이 거의 불가능하다.

 

windows 는 당연히 쓰레드를 지원한다.

 

 

 

각기 다른 기능을 갖는 무한 반복문 while_1 과 while_2 가 있다고 하자.

 

소스파일에서 while_1 을 쓰레드로 정의해두고,

 

메인 함수에서 쓰레드를 호출하게 되면

 

while_1은 자기 기능만 계속 수행하게 되고,

 

while_2도 자기 기능만 계속 수행하게 된다.

 

즉, 하나의 소스파일로 두개의 프로그램이 실행되게 할 수 있다는 것이다.

 

 

쓰레드 1을 호출한 후에는

 

각각 따로 실행된다.

 

쓰레드를 선언하면 선언할 수록 여러 코드를 동시에 실행시킬 수 있다.

 

 

 

 

 

 

 

 

코드

#include <stdio.h>
#include <Windows.h>
#include <process.h>

unsigned _stdcall Thread_A(void* arg)
{
	while (1)
	{
		printf("A");
		Sleep(1000);
	}
}

int main(void)
{
	_beginthreadex(NULL, 0, Thread_A, 0, 0, NULL);

	while (1)
	{
		printf("B");
		Sleep(2000);

		
	}
	return 0;
}

 

 

 

 

 

 

 

 

실행 결과

 

BAA 가 반복적으로 출력된다.

 

 

 

 

해석


#include <stdio.h>
#include <Windows.h>
#include <process.h>

우선 헤더 파일에 Windows.h 와 process.h 를 추가로 불러와야 한다.

Windows.h 에는 Sleep( ) 이라는 딜레이 함수가 있고,

process.h 에는 쓰레드를 사용할 수 있는 기능이 있다.

 

 

unsigned _stdcall Thread_A(void* arg)
{
   while (1)
   {
      printf("A");
      Sleep(1000);
   }
}

 

위와 같이 선언하면 Thread_A 라는 이름의 쓰레드를 만드는 것이다.

그 아래에는 쓰레드에 대해서 정의를 하면 된다.

 

A 를 1초마다 출력하는 기능을 하도록 하였다.

 

 

 

 

 

int main(void)
{
   _beginthreadex(NULL, 0, Thread_A, 0, 0, NULL);

   while (1)
   {
      printf("B");
      Sleep(2000);
   }
   return 0;
}

 

 

_beginthreadex 이라는 명령을 통해서 선언했던 Thread_A 를 호출하라고 명령한다.

 

그리고 바로 main 기능인

B를 2초마다 출력하라고 지시하였다.

 

 

 

코드는 위에서 아래로 한 줄 한 줄 작동하며 내려오기 때문에

 

Thread_A가 먼저 실행 되어야 하는거 아닌가 싶다.

 

하지만 결과를 보면 B가 먼저 출력되는 것을 볼 수 있는데,

 

그 이유로는 로딩 때문이라고 본다.

 

만약 Thread_A가 게임 '배그' 라고 하고

 

본문이 웹브라우저 '크롬' 이라고 하자.

 

배그를 먼저 실행시키고 곧바로 크롬을 실행시킨경우

 

배그는 로딩때문에 오래 걸리는데,

 

크롬은 바로 실행되게 된다.

 

따라서 배그를 먼저 켰어도 로딩때문에 늦게 실행될 수 있는 것과 같은 원리다.

 

Thread_A 를 호출해서 실행시키는 사이에 Main이 먼저 실행되는 것이다.

 

간단하게 테스트 하려면 main이 실행되기 전에 Sleep(1000)을 입력하면

 

A가 먼저 출력되는 것을 볼 수 있다.

 

 

 

 

 

결론

컴퓨터에서는 무한 반복문 여러개를 동시에 각각 실행시킬 수 있다.

 

이 개념을 쓰레드라고 부른다. (멀티 쓰레드)

 

각각 독립실행 이지만, 너무 많은 쓰레드를 사용하면 스케쥴러가 꼬여서 성능이 더 떨어질 수 있다.

 

하나의 소스파일로 여러가지 실행을 할 수 있다.

 

 

 

 

 

 

 

도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!

감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^

댓글