콜백 함수를 사용하는 많은 경우에 콜백 함수에 들어갈 인자를 정해줄 수 있다. 그런 예 중에 하나가 CreateThread인데, 쓰레드 몸통이 될 함수에 콜백 인자를 하나 줄 수 있다. 클래스의 멤버를 콜백으로 사용하지 못하는 이유가 바로 this가 없다는 점인데(콜백 함수를 호출하는 쪽에서 무슨 인스턴스의 멤버를 호출할 지 어떻게 알겠는가), 이 콜백 인자로 this를 주고 이 인스턴스에 접근하면 멤버 변수고 함수고 마음대로 쓸 수 있을 것이다.

백 마디 말보다 한 줄 코드가 낫다는 격언에 따라 코드를 풀어보면,

class ThreadObject
{
protected:
      static DWORD WINAPI _ThreadProc(LPVOID lpParam)
      {
             ThreadObject* _this=(ThreadObject*)lpParam;
             return _this->ThreadProc(_this->thread_param);
      }
      HANDLE thread_handle;
      DWORD thread_id;
      LPVOID thread_param;

      // ....
public:
      ThreadObject(LPVOID thread_param=NULL)
      {
            this->thread_param=thread_param;
            thread_handle=CreateThread(NULL,0,&ThreadObject::_ThreadProc,this,0,&thread_id);
      }
      DWORD ThreadProc(LPVOID lpParam)
      {
            //  do something
            return 0;
      }

      // ....
};

대충 이런 모양이 될 것이다.

생성자의 CreateThread에서 ThreadProc을 바로 콜백으로 줄 수 없으므로 _ThreadProc이란 더미 콜백을 주고, 그 콜백의 인자로 현재 객체의 주소(this)를 준다. 더미 콜백에선 인자로 넘어온 값을 캐스팅하여 this 포인터를 구하고 인스턴스의 멤버함수를 호출한다. 이렇게 하면 중간에 더미 콜백이 끼었지만 결과적으론 ThreadProc 멤버함수를 쓰레드 함수로 사용하는 효과를 낼 것이다.

꼭 CreateThread뿐만이 아니더라도 콜백에 인자를 줄 수 있는 경우엔 손쉽게 멤버 함수를 콜백으로 사용하도록 구현할 수 있다.

출처 : 디-
Posted by 명혀니
,