Re[2]: Выполнить функцию в другом потоке
От: Amor Россия  
Дата: 28.06.04 07:02
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Использовать функторы, например, boost::function + boost::bind.


Сочинил вот такой код, только вот почему-то не могу скомпилить его.
class IRefCounter
{
public:
     virtual void AddRef() = 0 ;
     virtual void Release() = 0 ;
};

// Макросы - фукнции реализации IRefCounter
#define REF_COUNTER_IMPLEMENTATION  \
     private: \
          int m_iCntr ; \
     public: \
          virtual void AddRef() \
          { \
               ++m_iCntr ; \
          } \
          virtual void Release() \
          { \
               if ( --m_iCntr <= 0 ) \
               { \
                    delete this ; \
               } \
          }
#define REF_COUNTER_INIT m_iCntr( 0 )

// Поток будет вызывать эту функцию
class ICall : public IRefCounter
{
public:
     virtual void Call() = 0 ;
//     virtual void Exception( std::exception& st ) = 0 ; ... наметки
};

// Это фукнция потока
enum { WM_CALL = WM_USER } ;
DWORD WINAPI ThrFunc( LPVOID pParam )
{
     MSG msg ;
     while ( GetMessage( &msg, 0, 0, 0 ) )
     {
          if ( msg.message == WM_CALL ) // Надо совершить вызов
          {
               ICall * pCall = ( ICall * ) msg.lParam ;
               try
               {
                    pCall->Call() ; // совершаем
                    if ( msg.wParam )
                    {
                         SetEvent( (HANDLE) msg.wParam ) ;
                    }
                    pCall->Release() ;
               }
               catch ( std::exception& )
               {
                    //pCall->Exception( st ) ;
               }
          }
     }

     return 0 ;
}

// Вызов неконстантной фукнции, возвращающей значение (не void), с двумя параметрами.
template< class _R, class BinOp, class _A1, class _A2 >
class CFunction2 : public ICall
{
     REF_COUNTER_IMPLEMENTATION
public:
     CFunction2( const BinOp& obj, _R ( BinOp::*pfn)(_A1,_A2), _A1 arg1, _A2 arg2 ) 
          : m_obj( obj )
          , m_pfn( pfn )
          , m_arg1( arg1 )
          , m_arg2( arg2 )
          , REF_COUNTER_INIT
     {}

     virtual void Call()
     {
          m_result = (m_obj.*m_pfn)( m_arg1, m_arg2 ) ;
     }

     typedef _R result_type ;
     _R m_result ;

protected:
     BinOp m_obj ;
     _R ( BinOp::*m_pfn )(_A1,_A2) ;
     _A1 m_arg1 ;
     _A2 m_arg2 ;
} ;

template< class _R, class BinOp, class _A1, class _A2 >
CFunction2< _R, BinOp, _A1, _A2 > * Function2( const BinOp& obj, _R ( BinOp::*pfn)(_A1,_A2), _A1 arg1, _A2 arg2 )
{
     CFunction2< _R, BinOp, _A1, _A2 > * p = new CFunction2< _R, BinOp, _A1, _A2 >( obj, pfn, arg1, arg2 ) ;
     p->AddRef() ;
     return p ;
}

// Также надо сделать.
// const_Function2, void_Function2, const_void_Function2... или механизм для void использовать (я уже встречал варианты реализации)
// И тоже самое для Function0, Function1, Function3 и, далее по мере необходимости.

class CTmp
{
public:
     int func2( int a, int b )
     {
          return a+b ;
     }
};

// Поток обслуживающий эти вызовы.
class CCaller
{
     DWORD dwThrId ;
     HANDLE hThread ;
public:
     // Конструктор - создаем поток.
     CCaller()
     {
          hThread = CreateThread( NULL, 0, ThrFunc, NULL, 0, &dwThrId ) ;
          Sleep( 1000 ) ;
     }
     // Деструктор - завершаем его.
     ~CCaller()
     {
          PostThreadMessage( dwThrId, WM_QUIT, 0, 0 ) ;
          WaitForSingleObject( hThread, INFINITE ) ;
          CloseHandle( hThread ) ;
     }

     // Совершить вывов функции нашем потоке.
     template< class BinObj >
     void Call( BinObj * pCall )
     {
          PostThreadMessage( dwThrId, WM_CALL, 0, ( LPARAM ) ( ICall * ) pCall ) ;
     }

     // Совершить вызов функции в потоке с ожиданием результата.
     template< class BinObj >
     typename BinObj::result_type Call_Wait( BinObj * pCall )
     {
          HANDLE hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ) ;
          pCall->AddRef() ;
          PostThreadMessage( dwThrId, WM_CALL, ( WPARAM )hEvent, ( LPARAM ) ( ICall * ) & pCall ) ;
          WaitForSingleObject( hEvent, INFINITE ) ;
          CloseHandle( hEvent ) ;
          typename BinObj::result_type res = rCall.m_result ;
          rCall.Release() ;
          return  res ;
     }
};

int main(int argc, char* argv[])
{
     CTmp tmp ;
     CCaller caller ;

     int res = caller.Call_Wait( Function2( tmp, &CTmp::func2, 2, 2 ) ) ;
/*
В строке выше - ошибка.
error C2893: Failed to specialize function template 'generic-type-271 __thiscall CCaller::Call_Wait(BinObj *)'
        With the following template arguments:
        'class CFunction2<int,class CTmp,int,int>'
*/

     caller.Call( Function2( tmp, &CTmp::func2, 2, 2 ) ) ;

     return 0;
}


В чем ошибка, подскажите, а то у меня уже....
Как вам вообще такая реализация.

Заранее благодарен.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.