类内的Boost Thread无法访问成员变量

时间:2014-01-13 19:40:35

标签: c++ multithreading winapi visual-studio-2008 boost-thread

我有一个动态实例化的类(因为指针在C接口中来回传递),它有一个成员提升线程。在成员函数中,执行以下代码:

_thrd = boost::thread( boost::bind( &cls::thrdProc, this, other vars ) );

我知道以下内容: 线程已创建 因为线程过程是同一类的非静态成员函数,所以“this”作为第一个参数传递。 我已经尝试过,有没有boost :: bind。

同样在该类中是我编写的队列的成员变量。线程过程创建一个隐藏的消息窗口,初始化通信库,并且当接收到数据时,库会向消息过程(在线程中)发送Windows消息。消息过程将消息调度到静态窗口过程,该过程将其重定向到与该线程相同的类的成员函数。接收消息并输入线程过程。问题在于其中队列似乎尚未初始化(实际上该类的所有成员变量都是无效的)。因此,由于线程过程和主应用程序代码在一段时间后使用boost :: mutex来保护队列数据(取决于通信库接收的数据包数量),我在boost::lock_guard上收到运行时错误(也试过boost::scoped_lock)。这是因为线程过程调用_queue.push试图锁定未初始化的互斥锁,因此BOOST_VERIFY会抱怨。

我已经阅读了几个提及线程副本参数的问题和示例,但参数不是问题。似乎this指向其他东西或者包装类对象不存在。但它确实可以确认原始指针是否有效。

是否还有其他副本问题我不知道? 提前谢谢!

        HEADER FILE

interface language_proxy
{
virtual int connectToQ( int * id ) = 0;
virtual int deconnectFromQ( int const id ) = 0;
virtual int startDataCollection() = 0;
virtual int stopDataCollection() = 0;
...
};

class CMyThread : public language_proxy
{
public:
    CMyThread( com lib args );

    int connectToQ( int * id );
    int deconnectFromQ( int const id );
    int startDataCollection();  
    int stopDataCollection();
    ...

protected:
    boost::mutex        _mutex;
    CMyQueue            _queue;
    boost::thread       _thrd;
    ...

    uint thrdProc( com lib args );
};


EXECUTABLE FILE(S)

int CMyThread::startDataCollection()
{
// guard against multiple starts
if( boost::thread:id() == _thrd.get_id() )
    {
    _thrd = boost::thread( boost::bind( &CMyThread::thrdProc, this, member vars for com lib ) );
    }
}

uint CMyThread::thrdProc( com lib args )
{
// create hidden messaging window
WNDCLASSEX                  wc                  = { 0 };

// many parameters can be ignored since window will be hidden
wc.cbSize        = sizeof( WNDCLASSEX );
wc.lpszClassName = MSG_WND_CLS;
wc.lpfnWndProc   = &CMyThread::StaticWndProc;
wc.hInstance     = GetModuleHandle( 0 );

// register the class with Windows
RegisterClassEx( &wc );

// create a window based on the above class parameters
_msg_hwnd = CreateWindowEx
                (
                0,
                wc.lpszClassName,
                L"HiddenMessageWindow",
                0,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                0,
                0,
                HWND_MESSAGE,
                0,
                0,
                this
                );

// initialize com lib

// process windows messages
while( true )
    {
    // process available messages
    if( PeekMessage( &msg, _msg_hwnd, 0, 0, PM_REMOVE ) )
        {
        // break out of the loop if the quit message is found
        if( WM_QUIT == msg.message )
            {
            printf( "Quit message found\n" );
            break;
            }

        TranslateMessage( &msg );
        DispatchMessage( &msg );
        }

    else
        {
        // throws boost::thread_interrupted if the thread has been interrupted
        boost::this_thread::sleep_for( boost::chrono::milliseconds( _msg_loop_dly ) );
        }
    }

UnregisterClass( MSG_WND_CLS, GetModuleHandle( 0 ) );
}

LRESULT CALLBACK CMyThread::StaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
CMyThread *         pWnd                = 0;

try
{
// store class pointer for window being created
if( WM_NCCREATE == uMsg )
    {
    // use SetWindowLongPtr to be 64-bit compatible ( a class pointer will be 64 bits and a long is only 32 bits )
    pWnd = ( CMyThread * )( ( LPCREATESTRUCT )lParam )->lpCreateParams;
    SetWindowLongPtr( hWnd, GWLP_USERDATA, *reinterpret_cast< LONG_PTR * >( pWnd ) );
    }

// access the class pointer
else
    {
    pWnd = ( CMyThread * )GetWindowLong( hWnd, GWL_USERDATA );
    }

// if a class pointer for the window exists, call its procedure
if( pWnd )
    {
    return( pWnd->WndProc( hWnd, uMsg, wParam, lParam ) );
    }
}

catch( ... )
{
int x = 5;
}

// call the default window procedure
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}

LRESULT CALLBACK CMyThread::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
    {
    // when a request to close the window is received, destroy the window
    case WM_CLOSE:
        {
        DestroyWindow( hWnd );
        } break;

    // when a window is destroyed put a quit message in the queue to stop message processing
    case WM_DESTROY:
        {
        PostQuitMessage( 0 );
        } break;

    // handle messages from com library
    case UWM_RX_COM_LIB_MSG:
        {
        // use GetWindowLongPtr to be 64-bit compatible ( a class pointer will be 64 bits and a long is only 32 bits )
        LONG_PTR            lPtr                = GetWindowLongPtr( hWnd, GWLP_USERDATA );
        CMyThread *         pWnd                = reinterpret_cast< CMyThread * >( &lPtr );
        pWnd->onRx();
        } break;

    // handle all other cases by default behaviour
    default:
        {
        return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
        }
    }

return( 0 );
}

void CMyThread::onRx()
{
// extract packet(s) from com library
// add packet(s) to vector

// THIS QUEUE IS UNINITIALIZED!
_queue.push( pkts );
}

int C_Interface_create
    (
    com lib arguments,
    language_proxy **   p
    )
{
// instantiate the C++ object through the C interface
language_proxy *        tmp_p       = new CMyThread( com lib args );

if( tmp_p )
    {
    *p = tmp_p;
    }

    return( 0 );
}

int C_Interface_start_thread( language_proxy * p )
{
p->startDataCollection();
    return( 0 );
}


// actually in a DLL but so you have some idea of what the operation flow is
void main()
{
static language_proxy *     s_proxy = 0;

C_Interface_create( 1, 2, 3, &s_proxy );
c_Interface_start_thread( s_proxy );

// for debugging, endless loop to allow rx'd packets to be processed and guarantee
// s_proxy is still alive
while( 1 );
}

1 个答案:

答案 0 :(得分:1)

很难说出你的问题实际上是什么,并且没有足够的代码可以确定,但从此判断:

  

问题在于它内部队列[通过指针传递给线程函数]似乎尚未初始化

一个可能的原因(再次,我猜是因为我没有任何事情继续),是你传递给线程的this指针实际上是指向本地实例化的自动指针随后在线程启动之前销毁的变量。

例如:

void MyQueue::startTheThread()
{
  _thrd = boost::thread( boost::bind( &cls::thrdProc, this, other vars ) );
}

int someFreeFunction()
{
  MyQueue q;
  q.startTheThread();
}

会复制我描述的行为。请注意,您实际看到的是未定义行为,因此任何事情都可能发生。