C++ Thread Class

maxswjeon의 이미지

C++ Thread Class 가 급히 필요해서 제작한 소스가 인자전달이 에러나네요....
일단 인자전달은 안되지만 실행은 되는 코드를 올려보긴 하겠습니다...
저는 아직도 Start부분에 Thread 생성을 CreateThread로 하는 게 마음에 걸리네요...
도와주세요

Thread.h

#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
class Thread
{
protected:
	HANDLE Handle;
	DWORD ID;
 
private:
	Thread(const Thread& bt);
	Thread& operator = (const Thread& bt) {};
	static DWORD WINAPI StaticThreadStart(LPVOID lpParam);
 
protected:
	virtual DWORD Run(void) = 0;
 
public:
	Thread();
	virtual ~Thread();
	bool Start();
	void Stop();
 
	inline HANDLE GetThreadHandle();
	inline DWORD GetThreadID();
	inline bool IsRunning();
	inline void Join();
	inline BOOL Yeild();
	inline void Sleep(DWORD dsMilliiseconds);
	inline DWORD Suspend();
	inline DWORD Resume();
};

Thread.cpp

#include "Thread.h"
 
#include <stdexcept>
 
using namespace std;
 
DWORD WINAPI Thread::StaticThreadStart(LPVOID lpParam)
{
	Thread* pThread = (Thread*)lpParam;
	return pThread->Run();
}
 
Thread::Thread() : Handle(NULL), ID(0)
{
 
}
 
Thread::~Thread()
{
	if (Handle) CloseHandle(Handle);
}
 
bool Thread::Start()
{
	if (Handle)
		{
		if (WaitForSingleObject(Handle, 0) == WAIT_TIMEOUT) {	// Thread Still Running
		return false;
		}
		CloseHandle(Handle);
	}
	Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread::StaticThreadStart, this, 0, &ID);
	if (Handle != NULL) return true;
	return false;
}
 
void Thread::Stop()
{
	if (this->IsRunning()) {
		::TerminateThread(Handle, -1);
	}
	if (Handle) {
		CloseHandle(Handle);
		Handle = NULL;
	}
}
 
inline HANDLE Thread::GetThreadHandle() {
	return Handle;
}
 
inline DWORD Thread::GetThreadID()
{
	return ID;
}
 
inline bool Thread::IsRunning()
{
	if (Handle) {
		DWORD dwExitCode = 0;
		::GetExitCodeThread(Handle, &dwExitCode);
		if (dwExitCode == STILL_ACTIVE) return true;
	}
	return false;
}
 
inline void Thread::Join()
{
	::WaitForSingleObject(Handle, INFINITE);
}
 
inline BOOL Thread::Yeild()
{
	return ::SwitchToThread();
}
 
inline void Thread::Sleep(DWORD dsMilliiseconds)
{
	::Sleep(dsMilliiseconds);
}
 
inline DWORD Thread::Suspend()
{
	return ::SuspendThread(Handle);
}
 
inline DWORD Thread::Resume()
{
	return ::ResumeThread(Handle);
}
shint의 이미지

이거 지우면 되네요.
// virtual DWORD Run(void) = 0;
순수가상함수라고 할겁니다.

#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
 
 
 
#include <stdexcept>
 
using namespace std;
 
 
class CPThread
{
public:
	CPThread(){}
	~CPThread(){}
 
	virtual DWORD Run(void) = 0;
};
 
 
class Thread : public CPThread
{
protected:
	HANDLE Handle;
	DWORD ID;
 
private:
	Thread(const Thread& bt);
	Thread& operator = (const Thread& bt) {};
	static DWORD WINAPI StaticThreadStart(LPVOID lpParam);
 
protected:
	virtual DWORD Run(void){}
 
public:
	Thread();
	virtual ~Thread();
	bool Start();
	void Stop();
 
	inline HANDLE GetThreadHandle();
	inline DWORD GetThreadID();
	inline bool IsRunning();
	inline void Join();
	inline BOOL Yeild();
	inline void Sleep(DWORD dsMilliiseconds);
	inline DWORD Suspend();
	inline DWORD Resume();
};
 
 
 
 
DWORD WINAPI Thread::StaticThreadStart(LPVOID lpParam)
{
	Thread* pThread = (Thread*)lpParam;
	return pThread->Run();
}
 
Thread::Thread() : Handle(NULL), ID(0)
{
 
}
 
Thread::~Thread()
{
	if (Handle) CloseHandle(Handle);
}
 
bool Thread::Start()
{
	if (Handle)
		{
		if (WaitForSingleObject(Handle, 0) == WAIT_TIMEOUT) {	// Thread Still Running
		return false;
		}
		CloseHandle(Handle);
	}
	Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread::StaticThreadStart, this, 0, &ID);
	if (Handle != NULL) return true;
	return false;
}
 
void Thread::Stop()
{
	if (this->IsRunning()) {
		::TerminateThread(Handle, -1);
	}
	if (Handle) {
		CloseHandle(Handle);
		Handle = NULL;
	}
}
 
inline HANDLE Thread::GetThreadHandle() {
	return Handle;
}
 
inline DWORD Thread::GetThreadID()
{
	return ID;
}
 
inline bool Thread::IsRunning()
{
	if (Handle) {
		DWORD dwExitCode = 0;
		::GetExitCodeThread(Handle, &dwExitCode);
		if (dwExitCode == STILL_ACTIVE) return true;
	}
	return false;
}
 
inline void Thread::Join()
{
	::WaitForSingleObject(Handle, INFINITE);
}
 
inline BOOL Thread::Yeild()
{
	return ::SwitchToThread();
}
 
inline void Thread::Sleep(DWORD dsMilliiseconds)
{
	::Sleep(dsMilliiseconds);
}
 
inline DWORD Thread::Suspend()
{
	return ::SuspendThread(Handle);
}
 
inline DWORD Thread::Resume()
{
	return ::ResumeThread(Handle);
}
 
 
int main ( int argc, char ** argv )
{
	Thread * ptd = NULL;
	ptd = new Thread();
	ptd->Start();
	ptd->Stop();
	delete ptd;
 
	return 0;
}

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

chanik의 이미지

Thread.cpp에 아래와 같이 몇 줄 샘플코드를 추가해보니 잘 동작하는 것 같습니다.
질문하신 인자전달에러라는 것이 무엇인지 재현이 가능한 간단한 코드를 올려주실 수 있나요?

#include <cstdio>
 
class ThreadTest : public Thread
{
protected:
	virtual DWORD Run(void)
	{
		for(int i=1; i<=5; i++)
		{
			Sleep(200);
			printf("[TID %d]\t: %d\n", GetThreadID(), i);
		}
 
		return 0;
	}
};
 
int main()
{
	ThreadTest t1, t2;
	if(t1.Start() && t2.Start())
	{
		t1.Join();
		t2.Join();
	}
 
	t1.Stop();
	t2.Stop();
 
	return 0;
}

V:\test\Thread>Thread.exe
[TID 1596]      : 1
[TID 5840]      : 1
[TID 1596]      : 2
[TID 5840]      : 2
[TID 1596]      : 3
[TID 5840]      : 3
[TID 1596]      : 4
[TID 5840]      : 4
[TID 1596]      : 5
[TID 5840]      : 5
maxswjeon의 이미지

이 소스는 정상 작동하는 소스입니다....
그런데 예를 들어 이 Thread를 어떤 렌데러를 실행시키려면 main 함수에서 이 Thread로 렌더러 포인터를 보내 주어야 하는 것인데,
이 소스에서는 렌더러를 줄 수 있는 방안이 없습니다....

그래서 Run부분에 void*형을 넣고 싶은데... 안되네요...
저는 그걸 도와주셨으면 합니다

언제나 감사드립니다

chanik의 이미지

아름다운 방법은 아니지만,
m_lpThreadParam 이라는 이름으로 void * 멤버변수를 하나 추가하고
Start() 멤버함수를 조금 바꾸면 간접적이나마 인자전달이 이뤄지겠네요.

수정한 Thread.h와 Thread.cpp를 올립니다.
바뀐 부분은 lpThreadParam 문자열을 검색하면 확인할 수 있습니다.

#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
class Thread
{
protected:
	HANDLE Handle;
	DWORD ID;
	LPVOID m_lpThreadParam;
 
private:
	Thread(const Thread& bt);
	Thread& operator = (const Thread& bt) {};
	static DWORD WINAPI StaticThreadStart(LPVOID lpParam);
 
protected:
	virtual DWORD Run(void) = 0;
 
public:
	Thread();
	virtual ~Thread();
	bool Start(LPVOID lpThreadParam);
	void Stop();
 
	inline HANDLE GetThreadHandle();
	inline DWORD GetThreadID();
	inline bool IsRunning();
	inline void Join();
	inline BOOL Yeild();
	inline void Sleep(DWORD dsMilliiseconds);
	inline DWORD Suspend();
	inline DWORD Resume();
};

#include "Thread.h"
 
#include <stdexcept>
 
using namespace std;
 
DWORD WINAPI Thread::StaticThreadStart(LPVOID lpParam)
{
	Thread* pThread = (Thread*)lpParam;
	return pThread->Run();
}
 
Thread::Thread() : Handle(NULL), ID(0)
{
 
}
 
Thread::~Thread()
{
	if (Handle) CloseHandle(Handle);
}
 
bool Thread::Start(LPVOID lpThreadParam)
{
	if (Handle)
		{
		if (WaitForSingleObject(Handle, 0) == WAIT_TIMEOUT) {	// Thread Still Running
		return false;
		}
		CloseHandle(Handle);
	}
	m_lpThreadParam = lpThreadParam;
	Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread::StaticThreadStart, this, 0, &ID);
	if (Handle != NULL) return true;
	return false;
}
 
void Thread::Stop()
{
	if (this->IsRunning()) {
		::TerminateThread(Handle, -1);
	}
	if (Handle) {
		CloseHandle(Handle);
		Handle = NULL;
	}
}
 
 
inline HANDLE Thread::GetThreadHandle() {
	return Handle;
}
 
inline DWORD Thread::GetThreadID()
{
	return ID;
}
 
inline bool Thread::IsRunning()
{
	if (Handle) {
		DWORD dwExitCode = 0;
		::GetExitCodeThread(Handle, &dwExitCode);
		if (dwExitCode == STILL_ACTIVE) return true;
	}
	return false;
}
 
inline void Thread::Join()
{
	::WaitForSingleObject(Handle, INFINITE);
}
 
inline BOOL Thread::Yeild()
{
	return ::SwitchToThread();
}
 
inline void Thread::Sleep(DWORD dsMilliiseconds)
{
	::Sleep(dsMilliiseconds);
}
 
inline DWORD Thread::Suspend()
{
	return ::SuspendThread(Handle);
}
 
inline DWORD Thread::Resume()
{
	return ::ResumeThread(Handle);
}
 
 
 
#include <cstdio>
 
class ThreadTest : public Thread
{
protected:
	virtual DWORD Run(void)
	{
		int nParam = *(int*)m_lpThreadParam;
		for(int i=1; i<=nParam; i++)
		{
			Sleep(200);
			printf("[TID %d]\t: %d\n", GetThreadID(), i);
		}
 
		return 0;
	}
};
 
int main()
{
	ThreadTest t1, t2;
	int nParam1 = 3;
	int nParam2 = 5;
	if(t1.Start((LPVOID)&nParam1) && t2.Start((LPVOID)&nParam2))
	{
		t1.Join();
		t2.Join();
	}
 
	printf("----------------\n");
 
	nParam1 = 2;
	nParam2 = 3;
	if(t1.Start((LPVOID)&nParam1) && t2.Start((LPVOID)&nParam2))
	{
		t1.Join();
		t2.Join();
	}
 
	t1.Stop();
	t2.Stop();
 
	return 0;
}

실행결과는 아래와 같이 나옵니다.
두 스레드가 각각 인자로 전달된 숫자만큼씩 루프돌고 종료되는 걸 보니
대충 동작은 되는 것 같습니다.

C:\test>Thread.exe
[TID 4160]      : 1
[TID 4268]      : 1
[TID 4268]      : 2
[TID 4160]      : 2
[TID 4160]      : 3
[TID 4268]      : 3
[TID 4160]      : 4
[TID 4160]      : 5
----------------
[TID 4952]      : 1
[TID 6092]      : 1
[TID 4952]      : 2
[TID 6092]      : 2
[TID 6092]      : 3
shint의 이미지

#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
 
 
 
#include <stdexcept>
 
using namespace std;
 
 
class CRun
{
public:
	CRun(){}
	~CRun(){}
	void fnRun()
	{
		puts("fnRun --------------");
		Sleep(500);
	}
};
 
 
class CPThread
{
public:
	CPThread(){}
	~CPThread(){}
 
	virtual DWORD Run(void) = 0;
};
 
 
class Thread : public CPThread
{
protected:
	HANDLE Handle;
	DWORD ID;
 
private:
	Thread(const Thread& bt);
	Thread& operator = (const Thread& bt) {};
	static DWORD WINAPI StaticThreadStart(LPVOID lpParam);
 
protected:
	virtual DWORD Run(void)
	{
		while(1)
		{
			m_cr.fnRun();
		}
	}
 
public:
	Thread();
	virtual ~Thread();
	bool Start();
	void Stop();
 
	inline HANDLE GetThreadHandle();
	inline DWORD GetThreadID();
	inline bool IsRunning();
	inline void Join();
	inline BOOL Yeild();
	inline void Sleep(DWORD dsMilliiseconds);
	inline DWORD Suspend();
	inline DWORD Resume();
 
	CRun m_cr;
	void fnSetRun(CRun cr)
	{
		m_cr = cr;
	}
};
 
 
 
 
DWORD WINAPI Thread::StaticThreadStart(LPVOID lpParam)
{
	puts("StaticThreadStart\n");
	Thread* pThread = (Thread*)lpParam;
	return pThread->Run();
}
 
Thread::Thread() : Handle(NULL), ID(0)
{
 
}
 
Thread::~Thread()
{
	if (Handle) CloseHandle(Handle);
}
 
bool Thread::Start()
{
	if (Handle)
	{
		if (WaitForSingleObject(Handle, 0) == WAIT_TIMEOUT)		// Thread Still Running
		{
			return false;
		}
		CloseHandle(Handle);
	}
	Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread::StaticThreadStart, this, 0, &ID);
 
	char buf[1024];
	sprintf(buf, "Thread Handle : %d\n", Handle);
	puts(buf);
 
	if (Handle != NULL)
	{
		return true;
	}
	return false;
}
 
void Thread::Stop()
{
	if (this->IsRunning()) {
		::TerminateThread(Handle, -1);
	}
	if (Handle) {
		CloseHandle(Handle);
		Handle = NULL;
	}
}
 
inline HANDLE Thread::GetThreadHandle() {
	return Handle;
}
 
inline DWORD Thread::GetThreadID()
{
	return ID;
}
 
inline bool Thread::IsRunning()
{
	if (Handle) {
		DWORD dwExitCode = 0;
		::GetExitCodeThread(Handle, &dwExitCode);
		if (dwExitCode == STILL_ACTIVE) return true;
	}
	return false;
}
 
inline void Thread::Join()
{
	::WaitForSingleObject(Handle, INFINITE);
}
 
inline BOOL Thread::Yeild()
{
	return ::SwitchToThread();
}
 
inline void Thread::Sleep(DWORD dsMilliiseconds)
{
	::Sleep(dsMilliiseconds);
}
 
inline DWORD Thread::Suspend()
{
	return ::SuspendThread(Handle);
}
 
inline DWORD Thread::Resume()
{
	return ::ResumeThread(Handle);
}
 
 
int main ( int argc, char ** argv )
{
	Thread * ptd = NULL;
	ptd = new Thread();
 
	CRun cr;
	ptd->fnSetRun(cr);
 
	ptd->Start();
 
	HANDLE Handle = ptd->GetThreadHandle();
 
	char buf[1024];
	sprintf(buf, "[Main] Thread Handle : %d\n", Handle);
	puts(buf);
 
	puts("[Main] WaitForSingleObject(Handle, INFINITE)");
	WaitForSingleObject(Handle, INFINITE);
 
	ptd->Stop();
	delete ptd;
 
	puts("exit");
	return 0;
}
 
 
 
 
 
댓글 첨부 파일: 
첨부파일 크기
Package icon test C++ Thread Class 연습.zip144.76 KB

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.