[xingAPI][차트 데이터 수집기 만들기](5) 작업 스레드 생성

반응형

이전 글에서 차트 데이터 수집기 개발을 위한 다이얼로그 화면 구성, 설정값 내부 변수 저장, 로그인 처리를 하였습니다.

이번 포스팅에서는 수집상태 화면을 완성하기 전에 내부에 작업 스레드를 생성하고 주식마스터 테이블을 생성 후 주식종목조회 TR을 이용하여 전체 주식종목을 메모리에 로딩해 보겠습니다.

 

1. 작업 스레드 생성하기

메인 다이얼로그에서 수집작업을 수행하면 코드가 실행되는 동안 GUI가 Freezing 상태가 되기 때문에 별도의 Worker Thread를 생성하도록 하겠습니다. MFC에서는 UI Thread와 Worker Thread를 생성할 수 있습니다. MFC에서의 스레드에 대한 정보는 아래 포스팅을 참고하세요.

2023.12.10 - [프로그래밍/C | C++] - [MFC] MFC 스레드 예제

 

[MFC] MFC 스레드 예제

이번 포스팅에서는 윈도 MFC 환경에서 사용가능한 두 가지 타입의 스레드에 대해 알아보고 생성/동기화/종료 방법을 예제를 통해 알아보겠습니다. 리눅스 환경에서 thread를 사용해 보신 분들은 pt

blog.noyecube.com

 

클래스명을 CThreadLooper라고 이름 짓고 아래와 같이 기본 뼈대 코드를 작성 후 App의 Init에서 Thread를 생성해 주면 UINT ThreadLooper()가 메인 App의 스레드에서 분리되어 별도 Thread로 실행됩니다.

Thread 생성 파라미터로 theApp 의 포인터를 넘겨주고, 작업 동기화를 위한 이벤트 핸들을 하나 생성하여 초기화를 해주면 됩니다. 이 이벤트 핸들의 조작을 통하여 ThreadLooper()를 실행/정지시킬 수 있습니다.

아래 그림과 같이 기본 코드 작성 후 AfxBeginThread로 실제 스레드를 생성합니다.

스레드가 생성되면 Loop 진입 후 WaitForSingleObject()에서 SUSPENDED 상태로 대기하게 됩니다.

스레드 클래스 헤더
스레드 클래스 구현부

스레드 생성 코드는 아래와 같이 작성합니다.

// datacollector.h 에 아래 구문 추가
#include "CThreadLooper.h"

CThreadLooper m_ThreadLooper;
CWinThread* m_pThreadLooper;	// 생성자에서 m_pThreadLooper = NULL 로 초기화해주세요.
// datacollector.cpp 의 InitDialog()에 아래 구문 추가

m_pThreadLooper = AfxBeginThread(m_ThreadLooper.ThreadLooper, (void*)&theApp);
if (NULL == m_pThreadLooper) {
	AfxMessageBox(_T("AfxBeginThread ThreadLooper Error.\nQuit Program."));
}

이제 생성한 작업스레드 내부에서 수집작업을 어떤 단계로 진행할 것인지에 대하여 구조를 잡을 차례입니다.

큰 맥락에서 각 상태를 정의하고 그에 맞는 뼈대코드를 작성하여 틀을 잡습니다.

작업 스레드가 생성되면 이벤트 대기 상태에 머무르게 됩니다. 이 때 데이터 수집 명령을 받으면 관련 메모리 초기화 후 주식마스터테이블을 받습니다. 그다음에 데이터 수집 단계를 시작하여 주식마스터테이블에서 수집 대상 종목을 가져와서 수집시작일-수집종료일에 해당하는 데이터 수집 작업을 수행합니다. 이때 사용자가 일시정지/작업중단을 명령하거나 수집 완료가 되면 다시 이벤트 대기상태로 빠집니다. 

state diagram

위 상태도를 반영하여 추가 코드를 작성하였습니다.

헤더 파일에 메인스테이트, 서브스테이트를 정의하고 STATE 관리를 위한 TST_STATE 구조체 정의, 그리고 Thread 상태를 관리할 Thread Control Block 구조체를 정의하였습니다. 큰 틀에서 생각나는 대로 적어둔 것이고 코드 작성중에 얼마든지 변경될 수 있는 상태입니다.

스테이트 정의

lRetSleepTime 변수는 thread sleep 타임을 결정하거나 다음 state로의 전이를 결정할 때 사용할 변수입니다.

증권사 서버로의 데이터 요청/수신이 비동기적으로 이루어지고 각 TR마다 초당/10분당 요청할 수 있는 횟수 제한이 있기 때문에 Request이후에 어느정도 대기가 필요한 경우에는 이 변수값을 조정하며 Thread의 Sleep Time을 결정합니다.

첫 상태는 아무 이벤트가 없는 상태, EVENT_WAIT상태이기 때문에 이벤트 핸들을 초기화해주고, STATE변수를 EVENT_WAIT으로 설정해 줍니다. 그다음에 Thread Loop가 시작되면 WaitForSingleObject에서 이벤트를 대기하는 상태로 스레드 대기 상태가 됩니다.

EVENT_WAIT상태에서는 이전 작업 계속 또는 첫 작업 시작에 의한 INIT 상태로의 전이가 가능하기 때문에 EVENT_WAIT에서 다음 상태로 넘어갈 때는 Old State값을 체크하여 INIT으로 갈지, 이전 상태로 돌아갈지를 결정합니다.

INIT 상태에서는 메모리초기화와 주식마스터테이블 수신을 하기로 하였는데 이를 위하여 SUB State를 정의해 두었습니다.

QUIT은 데이터 수집작업이 완료되면 넘어오는 일시적인 상태인데 여기서 STATE를 Thread가 처음 생성될 때 기준으로 초기화를 해주고 이벤트 역시 Reset 해줍니다.

스테이트 머신 구현부

 

이상으로 차트데이터 수집을 위하여 별도의 작업 스레드를 생성하고 스테이트머신 방식으로 코드를 작성하는 예제를 알아보았습니다.

반응형