๋ฐ˜์‘ํ˜•

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ์ž‘์—…์ž ์Šค๋ ˆ๋“œ์™€ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•œ ์†Œ๊ฐœ๋ฅผ ํ–ˆ์—ˆ๋Š”๋ฐ์š”.
2019/08/31 - [MFC] ์ž‘์—…์ž ์Šค๋ ˆ๋“œ์™€ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์Šค๋ ˆ๋“œ

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ž‘์—…์ž ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
โ€ป ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ๋ณธ๋ฌธ ํ•˜๋‹จ์— ์ฒจ๋ถ€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

MFC์—์„œ๋Š” AfxBeginThread!

๋„์„œ๋‚˜ MFC Thread์— ๊ด€ํ•œ ๊ธ€๋“ค์„ ๋ณด๋ฉด ๋ณดํ†ต CreateThread, _beginthread, AfxBeginThread์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๋Š”๋ฐ์š”. ๊ฒฐ๋ก ์ ์œผ๋กœ, MFC ๊ด€๋ จ ํด๋ž˜์Šค ๋ฐ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” AfxBeginThread๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ณธ๋ฌธ์—์„œ๋Š” ๊ฐ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ํ•จ์ˆ˜์— ๋Œ€ํ•ด์„œ๋Š” ์„ค๋ช…์„ ์ƒ๋žตํ•˜๊ณ , ์‹ค์ œ MFC์—์„œ ์Šค๋ ˆ๋“œ๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์†Œ๊ฐœํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

AfxBeginThread ์†Œ๊ฐœ

API ์ •์˜: https://docs.microsoft.com/ko-kr/previous-versions/s3w9x78e(v=vs.140)
์ž‘์—…์ž ์Šค๋ ˆ๋“œ ์˜ˆ์ œ: https://docs.microsoft.com/ko-kr/cpp/parallel/multithreading-creating-worker-threads?view=vs-2019

AfxBeginThread ํ•จ์ˆ˜์˜ ์ฃผ์š” ์ธ์ž๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

CWinThread* AfxBeginThread(
   AFX_THREADPROC pfnThreadProc,
   LPVOID pParam,
   int nPriority = THREAD_PRIORITY_NORMAL,
   UINT nStackSize = 0,
   DWORD dwCreateFlags = 0,
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL 
);

CWinThread*
์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ๋œ ์Šค๋ ˆ๋“œ ๊ฐ์ฒด์˜ ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์‹คํŒจํ•˜๋ฉด NULL์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

pfnThreadProc
์ž‘์—…์ž ์Šค๋ ˆ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ „์—ญ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

pParam
pfnThreadProc ํ•จ์ˆ˜๋กœ ๋„˜๊ธธ ์ธ์ž๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ์™ธ์˜ ์˜ต์…˜์€ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์„ค์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ ์ƒ์„ฑ๊ณผ ํ•ด์ œํ•˜๊ธฐ

๊ทธ๋Ÿผ ์ด์ œ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๊ณ  ํ•ด์ œํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๋ฐ›์€ ์Šค๋ ˆ๋“œ ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์œ„ํ•œ CWinThread* ์ธ์Šคํ„ด์Šค์™€ ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋ฐ˜๋ณต ์ž‘์—…(while๋ฌธ)์„ ์œ„ํ•œ ๋ถ€์šธ(bool) ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

//header file
public:
	CWinThread* m_pThread;
	bool m_isWorkingThread;

๊ทธ๋ฆฌ๊ณ  ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ์ „์—ญ ํ•จ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด์„œ ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…์„ ์œ„ํ•ด ๋ฃจํ”„(loop)๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ while๋ฌธ์„ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ ์ถ”ํ›„ ์ข…๋ฃŒ๋ฅผ ์œ„ํ•œ bool ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

//source file
UINT ThreadForCounting(LPVOID param)
{
	CExamWorkerThreadDlg* pMain = (CExamWorkerThreadDlg*)param;

	while (pMain->m_isWorkingThread)
	{
		Sleep(30);

		//Do something...
	}

	return 0;
}

์Šค๋ ˆ๋“œ ์ƒ์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด์„œ ๋ฃจํ”„๊ฐ€ ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” bool ๋ณ€์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ true๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

//source file
m_isWorkingThread = true;

m_pThread = AfxBeginThread(ThreadForCounting, this);

์Šค๋ ˆ๋“œ ํ•ด์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค. bool ๋ณ€์ˆ˜๋ฅผ false๋กœ ์„ค์ •ํ•˜๋ฉด ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜ ๋‚ด์˜ ๋ฃจํ”„๊ฐ€ ๋๋‚˜๊ณ , 0์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ์ข…๋ฃŒ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋•Œ๊นŒ์ง€ ์Šค๋ ˆ๋“œ์˜ ํ•ธ๋“ค์„ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ์œ„ํ•ด WaitForSingleObject๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž„์•„์›ƒ์€ ์˜ˆ์‹œ๋กœ 5์ดˆ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์˜ํ•  ์ ์œผ๋กœ ํƒ€์ž„์•„์›ƒ์„ INFINITE๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ, ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜ ๋‚ด์˜ ๋ฃจํ”„๊ฐ€ ๋๋‚˜์ง€ ์•Š๊ฒŒ ๋˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ๋ฉˆ์ถฐ๋ฒ„๋ฆฌ๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

//source file
m_isWorkingThread = false;

WaitForSingleObject(m_pThread->m_hThread, 5000);

์ด ์™ธ์—๋„ ์Šค๋ ˆ๋“œ ํ•ด์ œ๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” GetExitCodeThread, TerminateThread, WaitForSingleObject ๋“ฑ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•๋“ค์ด ์žˆ๋Š”๋ฐ์š”. ๊ฐ•์ œ์ ์ธ ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ฆญ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ์‹œ์Šคํ…œ์—์„œ ๋ฆฌ์†Œ์Šค๊ฐ€ ํ•ด์ œ๋˜์ง€ ์•Š์•„ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‚จ์•„ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ์€ ์ •์ƒ์ ์œผ๋กœ ์ข…๋ฃŒ๋˜์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ ๋ฆญ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๊ณ  ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜์˜ ๋ฐ˜๋ณต ์ž‘์—…์ด ํ™•์‹คํ•˜๊ฒŒ ์ข…๋ฃŒ๋˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ bool ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ˆซ์ž๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์Šค๋ ˆ๋“œ ์˜ˆ์ œ

๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ˆซ์ž๋ฅผ 0๋ถ€ํ„ฐ ์นด์šดํŒ… ํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ Static text์™€ Button์„ ๋ฐฐ์น˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

UI ๋ฐฐ์น˜

ํ—ค๋” ํŒŒ์ผ์—๋Š” 1์”ฉ ์ฆ๊ฐ€๋˜๋Š” int ๋ณ€์ˆ˜์™€ UpdateCount๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜์—์„œ PostMessage๋ฅผ ๋ฐ›๊ฒŒ ๋˜์–ด UI์— ์ ‘๊ทผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์™œ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.
[MFC] SendMessage์™€ PostMessage์˜ ์ฐจ์ด (์˜ˆ์ œ ์ฝ”๋“œ ํฌํ•จ)

//header file
#define MESSAGE_INCREASE_COUNT WM_USER

public:
	CWinThread* m_pThread;
	bool m_isWorkingThread;
	int m_nCount;
	LRESULT UpdateCount(WPARAM wParam, LPARAM lParam);

์†Œ์Šค ํŒŒ์ผ์—์„œ Message Map์— ์ •์˜ํ•œ PostMessage๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ON_MESSAGE๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

//source file
BEGIN_MESSAGE_MAP(CExamWorkerThreadDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_THREAD, &CExamWorkerThreadDlg::OnBnClickedButtonThread)
	ON_MESSAGE(MESSAGE_INCREASE_COUNT, &CExamWorkerThreadDlg::UpdateCount)
END_MESSAGE_MAP()

๊ทธ๋ฆฌ๊ณ  ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. PostMessage๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์œ„ UpdateCount ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

//source file
UINT ThreadForCounting(LPVOID param)
{
	CExamWorkerThreadDlg* pMain = (CExamWorkerThreadDlg*)param;

	while (pMain->m_isWorkingThread)
	{
		Sleep(30);

		PostMessage(pMain->m_hWnd, MESSAGE_INCREASE_COUNT, NULL, NULL);
	}

	return 0;
}

์ˆซ์ž๋ฅผ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋Š” UpdateCount ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

//source file
LRESULT CExamWorkerThreadDlg::UpdateCount(WPARAM wParam, LPARAM lParam)
{
	CString text;
	text.Format(_T("%d"), m_nCount++);

	SetDlgItemText(IDC_STATIC_COUNT, text);

	return 0;
}

๋งˆ์ง€๋ง‰์œผ๋กœ ์Šค๋ ˆ๋“œ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑ๊ณผ ํ•ด์ œํ•˜๋Š” ๋ฒ„ํŠผ ์ด๋ฒคํŠธ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

//source file
void CExamWorkerThreadDlg::OnBnClickedButtonThread()
{
	CString caption;
	GetDlgItemText(IDC_BUTTON_THREAD, caption);

	if (caption == _T("Start"))
	{
		m_isWorkingThread = true;

		m_pThread = AfxBeginThread(ThreadForCounting, this);

		SetDlgItemText(IDC_BUTTON_THREAD, _T("Stop"));
	}
	else
	{
		m_isWorkingThread = false;

		WaitForSingleObject(m_pThread->m_hThread, 5000);

		SetDlgItemText(IDC_BUTTON_THREAD, _T("Start"));
	}
}

๋„ˆ๋ฌด๋‚˜ ๊ฐ„๋‹จํ•˜์ฃ ? ์ž์„ธํ•œ ์ฝ”๋“œ ๊ตฌํ˜„์€ ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

ExamWorkerThread.zip
0.13MB

 

๋ฐ˜์‘ํ˜•