100分关于两个新启动的线程的同步,同时loading不受到影响,如何处理?

dotnet90 2012-06-05 10:54:44
我想导出数据库的记录,同时下载该记录的附件,先启动了一个窗口显示loading
导出数据库记录的时候启动了一个线程,执行到下载附件的时候在该线程中又启动了一个新的线程,
在下载附件的时候让导出数据库的线程等待,附件下载的线程执行完毕,通知导出记录的线程执行下一条记录,如此反复,
我用WaitForSingleObject SuspendThread() 这些方式都能造成loading窗口的ontimer不能执行,请问如何做到互相协调,同步工作?
...全文
105 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
anmychen2001 2012-06-05
  • 打赏
  • 举报
回复
在上面这个例子中,我在线程中是每过一段时间就去获取下数据.(run函数)
外部获取数据是根据函数调用的,是其他线程调的.(RefreshRoomInfoM函数和SetUserLocateM函数)
anmychen2001 2012-06-05
  • 打赏
  • 举报
回复
我自己写的一个异步从网上获取数据,本地定时读取的程序.你要用要自己稍微改点
VrLocatRecordCL::VrLocatRecordCL(void)
{
m_pLocationClient = NULL ;
m_UserId[0] = '\0' ;
m_TeamId[0] = '\0' ;

m_hRunThread = NULL ;
m_ThreadId = 0 ;
m_hTimer = CreateWaitableTimer( NULL , FALSE , NULL ) ;
m_evntStop = CreateEvent( NULL , TRUE , TRUE , NULL ) ;
m_bRun = FALSE ;

InitializeCriticalSection( &m_SetSect ) ;
InitializeCriticalSection( &m_GetSect ) ;
}

VrLocatRecordCL::~VrLocatRecordCL(void)
{
LeaveRoomM() ;

destroyM() ;

DeleteCriticalSection( &m_SetSect ) ;
DeleteCriticalSection( &m_GetSect ) ;
}

//初始
BOOL VrLocatRecordCL::InitM( IConnectInterfaceCL * pConnect )
{
clearM() ;

if( pConnect != NULL )
{
m_pLocationClient = pConnect->GetLocationClientM() ;

BOOL bRtn = pConnect->GetUserInfoM( m_UserId, m_TeamId ) ;

if( m_hRunThread == NULL )
{
ResetEvent( m_evntStop ) ;
m_hRunThread = CreateThread( NULL, 0,
(LPTHREAD_START_ROUTINE)runProc,
(LPVOID)(this),
0,
&m_ThreadId ) ;
}
return bRtn ;
}

return FALSE ;
}

void VrLocatRecordCL::SetRunStatusM( BOOL bRun )
{
m_bRun = bRun ;
}

//获取本机用户ID
LPCTSTR VrLocatRecordCL::GetUserIdM()
{
return m_UserId ;
}

int VrLocatRecordCL::GetUserAtM()
{
return m_CurRoomId ;
}

//获取本机用户所在场景内的用户信息
BOOL VrLocatRecordCL::RefreshRoomInfoM()
{
lock( &m_GetSect ) ;

clearM() ;

int len = (int)m_TmpInfoLst.size() ;

m_LocalInfoLst.resize( len ) ;

for( int i = 0 ; i < len ; i++ )
{
m_LocalInfoLst[i] = m_TmpInfoLst[i] ;
}

unlock( &m_GetSect ) ;

return TRUE ;
}

//获取人数
int VrLocatRecordCL::GetUserCountM()
{
return (int)m_LocalInfoLst.size() ;
}

BOOL VrLocatRecordCL::GetUserIdbyIdxM( int idx, TCHAR * uId )
{
if( idx >= 0 && idx < (int)m_LocalInfoLst.size() )
{
_tcscpy_s( uId, 50, m_LocalInfoLst[idx].uId ) ;
return TRUE ;
}

return FALSE ;
}

BOOL VrLocatRecordCL::GetUserLocateM( LPCTSTR uId, float pos[3], float &angle )
{
for( int i = 0 ; i < (int)m_LocalInfoLst.size() ; i++ )
{
if( _tcscmp( uId, m_LocalInfoLst[i].uId ) == 0 )
{
pos[0] = m_LocalInfoLst[i].x ;
pos[1] = m_LocalInfoLst[i].y ;
pos[2] = m_LocalInfoLst[i].z ;
angle = m_LocalInfoLst[i].angle ;

return TRUE ;
}
}

return FALSE ;
}

//设置本机用户的位置
void VrLocatRecordCL::SetUserLocateM( const float pos[3], float angle )
{
lock( &m_SetSect ) ;

m_UserLocalInfo.x = pos[0] ;
m_UserLocalInfo.y = pos[1] ;
m_UserLocalInfo.z = pos[2] ;

m_UserLocalInfo.angle = angle ;

unlock( &m_SetSect ) ;
}

//进入房间
void VrLocatRecordCL::EnterRoomM( int roomId )
{
m_CurRoomId = roomId ;

float pos[3], angle ;

pos[0] = pos[1] = pos[2] = 0.0f ;
angle = 180.0f ;

SetUserLocateM( pos, angle ) ;

m_bRun = TRUE ;
}

//离开房间
void VrLocatRecordCL::LeaveRoomM()
{
m_bRun = FALSE ;

if( m_pLocationClient != NULL )
{
_variant_t varParam[1] ;
varParam[0] = _bstr_t( m_UserId ) ; //用户ID
m_pLocationClient->SetDataM( L"LeaveUser", varParam, 1 ) ;
}
}

void VrLocatRecordCL::clearM()
{
m_LocalInfoLst.clear() ;
}

DWORD VrLocatRecordCL::runProc( LPVOID lpParameter )
{
CoInitialize(NULL) ;

VrLocatRecordCL * pInst = ( VrLocatRecordCL* )lpParameter ;
if( pInst != NULL )
{
pInst->run() ;
}

CoUninitialize() ;

return 0L ;
}

void VrLocatRecordCL::run()
{
HANDLE hdls[2] ;
hdls[0] = m_hTimer ;
hdls[1] = m_evntStop ;

LARGE_INTEGER stTime ;
stTime.QuadPart = Int32x32To64( 500, -10000 ) ; //500ms

do
{
if( m_bRun == TRUE )
{
setUserLacateDataM() ;
getRoomLacateDataM() ;
}

SetWaitableTimer( m_hTimer , &stTime , 0 , NULL , NULL , FALSE ) ;

if( WAIT_OBJECT_0 != WaitForMultipleObjects( 2, hdls, FALSE, INFINITE ) )
{
break ;
}

} while( 1 ) ;
}

void VrLocatRecordCL::destroyM()
{
if( m_hRunThread != NULL )
{
SetEvent( m_evntStop ) ;

if( WAIT_FAILED == WaitForSingleObject( m_hRunThread, 1000 ) )
{
TRACE0( "Failed to End process!\r\n" ) ;
}

CloseHandle( m_hRunThread ) ;

m_hRunThread = NULL ;
}
}

void VrLocatRecordCL::setUserLacateDataM()
{
if( m_pLocationClient != NULL )
{
lock( &m_SetSect ) ;

_variant_t varParam[7] ;

varParam[6] = _bstr_t( m_UserId ) ; //用户ID
varParam[5] = _bstr_t( m_TeamId ) ; //TEAMID
varParam[4] = _bstr_t( m_CurRoomId ) ; //车间ID
varParam[3] = (double)m_UserLocalInfo.x ; //X坐标的值
varParam[2] = (double)m_UserLocalInfo.y ; //Y坐标的值
varParam[1] = (double)m_UserLocalInfo.z ; //Z坐标的值
varParam[0] = (double)m_UserLocalInfo.angle ; //视点的角度

unlock( &m_SetSect ) ;

m_pLocationClient->SetDataM( L"SubmitUserLocation", varParam, 7 ) ;
}
}

void VrLocatRecordCL::getRoomLacateDataM()
{
if( m_pLocationClient != NULL )
{
MyXmlDocumentCL vXML ;
_variant_t varParam[2] ;

varParam[1] = _bstr_t( m_TeamId ) ; //TEAMID
varParam[0] = _bstr_t( m_CurRoomId ) ; //RoomID

if( m_pLocationClient->GetDataM( L"GetUserLocationList", varParam, 2, &vXML ) )
{
lock( &m_GetSect ) ;

m_TmpInfoLst.clear() ;

MSXML2::IXMLDOMDocumentPtr pDoc = vXML.GetDocumentM() ;
if( pDoc != NULL )
{
MSXML2::IXMLDOMNodePtr pNode = pDoc->selectSingleNode( _bstr_t("WorkshopLocationList") );
MSXML2::IXMLDOMNodeListPtr pNodeLst = pNode->selectNodes( _bstr_t("Item") );

int len = pNodeLst->Getlength() ;

for( int i = 0 ; i < len ; i++ )
{
MSXML2::IXMLDOMNodePtr pTempNode = pNodeLst->item[i] ;

USER_LOCAL_INFOD info ;

vXML.GetNodeAttributeTCharM( pTempNode, _bstr_t("UserId"), info.uId, 50 ) ;
vXML.GetNodeAttributeFloatM( pTempNode, _bstr_t("LocationX"), &info.x ) ;
vXML.GetNodeAttributeFloatM( pTempNode, _bstr_t("LocationY"), &info.y ) ;
vXML.GetNodeAttributeFloatM( pTempNode, _bstr_t("LocationZ"), &info.z ) ;
vXML.GetNodeAttributeFloatM( pTempNode, _bstr_t("ViewAngle"), &info.angle ) ;

if( _tcscmp( m_UserId, info.uId ) != 0 ) //自己的位置信息不用从网上获取
{
m_TmpInfoLst.push_back( info ) ;
}
}
}
unlock( &m_GetSect ) ;
}
}
}

void VrLocatRecordCL::lock( CRITICAL_SECTION * pSect )
{
EnterCriticalSection( pSect );
}

void VrLocatRecordCL::unlock( CRITICAL_SECTION * pSect )
{
LeaveCriticalSection( pSect );
}
kyotrue 2012-06-05
  • 打赏
  • 举报
回复
WaitForSingleObject会阻塞的啊,你在OnTimer里面WaitForSingleObject,设置超时为0就行了
Eleven 2012-06-05
  • 打赏
  • 举报
回复
线程同步啊,临界区,事件对象,互斥对象。。。
「已注销」 2012-06-05
  • 打赏
  • 举报
回复
有两个简单的方法。

1. worker线程完成后向界面线程post消息,在界面线程里,需要等待的地方track消息,写法为

MSG m;
while( GetMessage(&m, 0, 0, 0) )
{
if(m.message == WM_XXXX) // 此处等待worker的完成消息
break;

TranslateMessage(&m);
DispatchMessage(&m);
}

2. 利用界面线程的处理空闲,轮询worker完成情况。 提供一个全局变量,类型为long volatile,表示worker的进度,worker应在完成一定的工作时,更新这个变量。 或者,不提供全局变量,仅在worker完成后自行exit线程。 在界面线程写法为:


while(true) {
MSG m;
while( PeekMessage(&m, ... , PM_REMOVE) )
{
TranslateMessage(&m);
DispatchMessage(&m);
}
// 此处进入空闲, 等待线程结束,超时为0
if(WaitForSingleObject( hThread, 0 ) == WAIT_OBJECT_0)
break;

}

dotnet90 2012-06-05
  • 打赏
  • 举报
回复
我用了waitforsingleobject导致loading不响应
fronz 2012-06-05
  • 打赏
  • 举报
回复
追求完美的话,尽量不要用ontimer,用变量做进度标准,
用事件驱动线程。执行到下载附件的时候,设置数据库线程挂起,执行完再继续。
oyljerry 2012-06-05
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

谢谢楼上 to:kyotrue 关键是我还想让读取记录的线程停住 让下载附件的线程完事 再执行
to:anmychen2001 你的代码 我先读读
[/Quote]
读取记录的线程WaitForSingleObject, 下载的线程执行完了,SetEvent让读取记录线程执行
dotnet90 2012-06-05
  • 打赏
  • 举报
回复
谢谢楼上 to:kyotrue 关键是我还想让读取记录的线程停住 让下载附件的线程完事 再执行
to:anmychen2001 你的代码 我先读读

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧