'2008/07'에 해당되는 글 2건

  1. 2008.07.26 SetThreadAffinityMask by 1stPasa
  2. 2008.07.26 Command Pattern - 일반화 구현 by 1stPasa

Thread Handle을 인수로 받아 특정 코어에서 해당 Thread를 실행하도록 지정해주는 함수.

0x01 부터 순서대로 한비트씩 쉬프트 하면 원하는 코어를 결정할수 있다.

주의할점은 하나의 Thread는 여러개의 코어가 모두 실행시킬수 있는데

만약 첫번째 코어와 두번째 코어가 모두 실행 가능하도록 설정하고 싶다면

01 과 10 의 OR 연산결과값인 0x03 을 설정하면 되는것이다.

만약 코어 1,2,3 에서 실행가능하게 하고 싶다면

001 , 010  그리고 100 를 OR 연산하여 호출해주면 된다.


아래의 코드는

SetThreadAffinityMask 를 테스트해보는 예제인데

주석처리된 부분을 그대로 두고 실행하면 재미있는 결과를 얻을수 있다.

실행하면 Core의 수를 출력한뒤 코어의 갯수에 해당하는 Thread를 생성하고

무한루프를 돌려서 CPU 점유율을 100%로 만들어 버린다.

그리고 콘솔창에서 숫자키 1~9까지의 숫자를 사용해 원하는 번호의 Thread를 정상종료

시킬수 있는데. 만약 듀얼코어에서 쓰레드 하나만 죽인다면 50%의 점유율을 차지하게 될것은

당연한 이치이지만. SetThreadAffinityMask 를 사용하지 않았을 경우와 사용했을 경우의

점유율 그래프를 본다면 이마를 탁 치게 될것이다. ( 벌써 알고 계셨다면.. 굳ㅋ )

#include <iostream>
#include <conio.h>
#include <windows.h>


using namespace std;

DWORD WINAPI ThreadProc(LPVOID arg)
{
 while( *((bool*)(arg))  )Sleep(0);

 return 0;
}

int main(int argc, char argv[])
{
 SYSTEM_INFO info;
 GetSystemInfo(&info);

 cout << info.dwNumberOfProcessors << endl;

 bool *flag = new bool[ info.dwNumberOfProcessors ];

 HANDLE *hTrhead = new HANDLE[info.dwNumberOfProcessors];

 for(int i = 0 ; i < info.dwNumberOfProcessors ; i++ )
 {
  flag[i] = true;
  hTrhead[i] = CreateThread(0,0,ThreadProc,&flag[i],0,0);
  //SetThreadAffinityMask( hTrhead[i]  , 1 << i );
 }


 char c;
 while(1)
 {
  c = getch();

  if( c >= '1' && c <= '9' )
   flag[ c-'1' ] = false;

  if( c == 13 )
   break;
 }

 return 0;
}

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지


가운데 있는 사진이 SetThreadAffinityMask 를 사용하지 않아서

코어가 쓰레드의 삽질을 같이 보듬어주고 있는경우고

아래의 사진은 SetThreadAffinityMask를 통해 하나의 코어가 하나의 쓰레드만 담당하여

2번째 쓰레드를 죽이고나니 개미와 베짱이를 연출시킨 상황이다.


Posted by 1stPasa

댓글을 달아 주세요

커맨드 패턴을 Function 과 Method 에 대해 일반화 하고

인수타입과 리턴타입에 대해서도 일반화 하였다.

한글이름도 어려운 명시적 템플릿 구체화까지 써가면서도

인수타입이 void 인경우에 대해 NoArg란 이름을 붙여 따로 정의할수밖에 없었던 이유는

생각지 못했던 Ambigious 문제가 발생했기 때문이다. ( 겪고보니 당연한 일이었지만.. )

결국 클래스의 종류는

Command ( 상위 클래스 )
MethodCommand, MethodCommandNoArg
FunctionCommand, FunctionCommandNoArg

다섯가지나 된다.. 사용할때 올바른 인스턴스를 만들어주는게 번거로우므로

MakeCommand 란 함수를 만들었는데 이것역시 템플릿 함수임에도 불구하고 4가지 버전이나 된다.

그놈의 void가 문제지.. return type 으로도 안되고 Argument로 넣을수도 없으니 별도로 구체화 시킬수밖에..ㅋ

아래는 그렇게 구현한 Command 패턴들과 MakeCommand 코드이다.

#pragma once
template <typename _A, typename _R>
class Command
{
public:
 virtual _R Fire(_A) = 0;
};

template<typename _T, typename _A, typename _R>
class MethodCommand : public Command<_A,_R>
{
 _T *m_obj;
 _R (_T::*m_mf)(_A);
public:
 MethodCommand(_T * object, _R (_T::*method)(_A)) : m_obj(object), m_mf(method) {}
 virtual inline _R Fire(_A arg){ return (m_obj->*m_mf)(arg);}
};

template<typename _T, typename _A>
class MethodCommand<_T,_A,void> : public Command<_A,void>
{
 _T *m_obj;
 void (_T::*m_mf)(_A);
public:
 MethodCommand(_T * object, void (_T::*method)(_A)) : m_obj(object), m_mf(method) {}
 virtual inline void Fire(_A arg){(m_obj->*m_mf)(arg);}
};

template <typename _T, typename _R>
class MethodCommandNoArg : public Command<void,_R>
{
 _T *m_obj;
 _R (_T::*m_mf)();
public:
 MethodCommandNoArg(_T * object, _R (_T::*method)()) : m_obj(object), m_mf(method) {}
 virtual inline _R Fire(void){ return (m_obj->*m_mf)();}
};

template <typename _T>
class MethodCommandNoArg<_T,void> : public Command<void,void>
{
 _T *m_obj;
 void (_T::*m_mf)();
public:
 MethodCommandNoArg(_T * object, void (_T::*method)()) : m_obj(object), m_mf(method) {}
 virtual inline void Fire(void){ (m_obj->*m_mf)();}
};

template <typename _A,typename _R>
class FunctionCommand : public Command<_A,_R>
{
 _R (*m_mf)(_A);
public:
 FunctionCommand(_R (*func)(_A)) : m_mf(func){}
 virtual inline _R Fire(_A arg){ return (*m_mf)(arg); }
};

template <typename _A>
class FunctionCommand<_A,void> : public Command<_A,void>
{
 void (*m_mf)(_A);
public:
 FunctionCommand(void (*func)(_A)) : m_mf(func){}
 virtual inline void Fire(_A arg){ (*m_mf)(arg); }
};

template <typename _R>
class FunctionCommandNoArg : public Command<void,_R>
{
 _R (*m_mf)(void);
public:
 FunctionCommandNoArg(_R (*func)(void)) : m_mf(func){}
 virtual inline _R Fire(void){ return (*m_mf)(); }
};

template <>
class FunctionCommandNoArg<void> : public Command<void,void>
{
 void (*m_mf)(void);
public:
 FunctionCommandNoArg(void (*func)(void) ) : m_mf(func){}
 virtual inline void Fire(void){ (*m_mf)(); }
};

template <typename _T, typename _A, typename _R>
Command<_A,_R>* MakeCommand( _T *target, _R (_T::*method)(_A) )
{
 return new MethodCommand<_T,_A,_R>( target, method );
}

template <typename _T, typename _R>
Command<void,_R>* MakeCommand( _T *target,  _R (_T::*method)(void) )
{
 return new MethodCommandNoArg<_T,_R>( target, method );
}

template <typename _A, typename _R>
Command<_A,_R>* MakeCommand( _R (*function)(_A) )
{
 return new FunctionCommand<_A,_R>( function );
}

template < typename _R>
Command<void,_R>* MakeCommand(_R (*function)(void) )
{
 return new FunctionCommandNoArg<_R>( function );
}

Command<_A , _R>  
-  _A : 인수 타입
-  _R : 반환 타입

간단하게 시작했는데 100줄을 넘겨버렸다.. ㅎㅎ

아래는 예제코드로서

void 와 void가 아닌 타입들을 대입할수 있다고 생각하면 되겠다.

위에서 말한것과 같이 void 의 경우 return 타입으로 쓸수 없기 때문에

return func1(); 과 같은 형태로 사용할수도 없고.

func1( arg ); 와 같은형태로 인수로 넣을수도 없다.

#include "Command.h"
#include <iostream>
using namespace std;

class MyClass
{
public:
 void method1()
 {
  cout << "void Method(void)" << endl;
 }

 int method2(int a)
 {
  cout << "int Method(int)" << endl;
  return a;
 }

 int method3(void* a)
 {
  cout << "int Method(void*)" << endl;
  return 10;
 }

 void method4(int a)
 {
  cout << "void Method(int)" << endl;
 }
};

void func1()
{
 cout << "void function(void)" << endl;
}

int func2(int a)
{
 cout << "int function(int)" << endl;
 return a;
}

int func3(void* a)
{
 cout << "int function(void*)" << endl;
 return 10;
}

void func4(int a)
{
 cout << "void function(int)" << endl;
}


int main(int argc, char* argv[])
{
 MyClass a;

 Command<void,void> *m1 = MakeCommand(&a, &MyClass::method1 );
 Command<int,int> *m2 = MakeCommand(&a, &MyClass::method2 );
 Command<void*,int> *m3 = MakeCommand(&a, &MyClass::method3 );
 Command<int,void> *m4 = MakeCommand(&a, &MyClass::method4 );
 
 Command<void,void> *f1 = MakeCommand(func1);
 Command<int,int> *f2 = MakeCommand(func2);
 Command<void*,int> *f3 = MakeCommand(func3);
 Command<int,void> *f4 = MakeCommand(func4);
 
 m1->Fire();
 m2->Fire(10);
 m3->Fire(NULL);
 m4->Fire(10);

 f1->Fire();
 f2->Fire(10);
 f3->Fire(NULL);
 f4->Fire(10);

 return 0;
}

생각같아선 C#의 델리게이트처럼 인수의 갯수도 일반화 시켜버리고 싶지만..

아무리 생각해도 인라인어셈을 동원하지 않고는 구현이 불가능한것 같다.

그렇게되면 컴파일타임 에러체크가 안되므로 패스하고

결국 이쯤에서 마무리를 짓는것이 좋을듯.
Posted by 1stPasa

댓글을 달아 주세요