类内的Boost Thread无法访问成员变量
Posted
技术标签:
【中文标题】类内的Boost Thread无法访问成员变量【英文标题】:Boost Thread inside class can't access member variables 【发布时间】:2014-01-13 19:40:35 【问题描述】:我有一个动态实例化的类(因为指针通过 C 接口来回传递),它有一个成员 boost 线程。在成员函数中执行以下代码:
_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 );
【问题讨论】:
哇,请减少文本长度或以更好的方式格式化它,但 IMO 不太可能有人会阅读这堵文字墙。 【参考方案1】:这里很难说出你的问题到底是什么,也没有足够的代码可以确定,但是从这个来看:
问题在于队列[通过指针传递给线程函数]似乎尚未初始化
造成这种情况的一个可能原因(我再次猜测,因为我无事可做)是您传递给线程的 this
指针实际上是一个指向本地实例化的自动变量的指针,它随后在您的线程启动之前被销毁。
例如:
void MyQueue::startTheThread()
_thrd = boost::thread( boost::bind( &cls::thrdProc, this, other vars ) );
int someFreeFunction()
MyQueue q;
q.startTheThread();
会复制我描述的行为。请注意,您实际看到的是未定义行为,因此任何事情都可能发生。
【讨论】:
感谢您尝试破译我的问题!这种可能性是有道理的,但我并不容易看到这一点。可能有与复制构造函数或赋值运算符有关的东西吗?两者都是所涉及的所有内容的默认值。以上是关于类内的Boost Thread无法访问成员变量的主要内容,如果未能解决你的问题,请参考以下文章