1.不能直接中断线程,应该设置一个标记,线程运行时检查这个标记
void CThreadSoap::ThreadRun()
{
RESULTTYPE rc(RC_SUCCESS);
//线程是否运行线程
bool is_run(false);
//线程要执行的动作
long thread_action(0);
//要执行动作的参数
void *lpActionPara( NULL );
//窗体句柄
HWND hWnd( NULL );
//gSaop对象
struct soap gSoap;
//获取线程是否运行
rc = this->CheckStatus( is_run,thread_action,&hWnd,&lpActionPara);
if( RC_SUCCESS != rc )
{
this->SetThreadError(rc);
return;
}
::soap_init(&gSoap);
while( is_run )
{
//检查是否执行动作
if( 0 != thread_action )
{
this->CallSoap( thread_action, gSoap,hWnd,lpActionPara );
this->ResetThreadAction();
this->SafePostMessage(hWnd,WM_SAOP_DONE,thread_action);
}
else
{
::Sleep(1);
}
//释放资源
hWnd = NULL;
CThreadBase::SafeFreeObject(lpActionPara);
//获取线程是否继续运行
rc = this->CheckStatus( is_run,thread_action,&hWnd,&lpActionPara);
if( RC_SUCCESS != rc )
{
this->SetThreadError( rc);
break;
}
}
//释放资源
CThreadBase::SafeFreeObject(lpActionPara);
::soap_done(&gSoap);
}
/获取线程执行动作的参数
RESULTTYPE CThreadBase::CheckStatus(bool &is_run,long &thread_action,HWND *lpHWnd,void **lppVal )
{
if( NULL == this->m_pthread_mutex || NULL == this->m_pthread_cond )
return ERR_INITIALIZE_FAIL;
bool thread_is_run(false); //线程是否运行
long thread_cur_action(0); //当前线程正在执行的动作
void *lpData( NULL ); //线程执行动作时的数据
HWND hWnd( NULL ); //窗体句柄
//锁定要读取的数据
::pthread_mutex_lock(&this->m_pthread_mutex);
if( 0 != this->m_ActionInfo.action )
{
//检查共享对象的有效性
if( this->m_ActionInfo.data.dwMemSize > 0 && NULL != this->m_ActionInfo.data.lpData)
{
//分配内存
lpData = malloc( this->m_ActionInfo.data.dwMemSize);
if( NULL == lpData )
{
::pthread_cond_signal( &this->m_pthread_cond );
::pthread_mutex_unlock(&this->m_pthread_mutex );
return ERR_MALLOC_FAIL;
}
memset( lpData,0x0, this->m_ActionInfo.data.dwMemSize );
memcpy(lpData,this->m_ActionInfo.data.lpData, this->m_ActionInfo.data.dwMemSize);
//当设置了动作参数时,当前线程复制对象完成后通知主线程释放资源
::pthread_cond_signal( &this->m_pthread_cond );
}
}
hWnd = this->m_ActionInfo.hWnd;
thread_cur_action = this->m_ActionInfo.action;
thread_is_run = this->m_ThreadRun;
::pthread_mutex_unlock(&this->m_pthread_mutex );
*lpHWnd = hWnd;
is_run = thread_is_run;
thread_action = thread_cur_action;
*lppVal = lpData;
return RC_SUCCESS;
}
RESULTTYPE CThreadBase::Stop()
{
if( NULL == this->m_pthread_mutex )
return ERR_INITIALIZE_FAIL;
::pthread_mutex_lock( &this->m_pthread_mutex );
this->m_ThreadRun = false;
::pthread_mutex_unlock(&this->m_pthread_mutex );
//等待线程运行完成
::pthread_join(this->m_pthread,NULL);
return RC_SUCCESS;
}
2.多线程对象应该配对使用,例如pthread_mutex_t和pthread_rwlock_t对象,同一对象不能在写的时候用互斥对象锁定,在读取的时间用读写锁锁定,应该是在读写时配对使用pthread_mutex_t对象或pthread_rwlock_t对象,例如上例中的Stop方法和CheckStatus配对使用pthread_mutex_lock
3.内存释放应遵循谁创建谁释放的原则.例如有线程A和线程B两个对象,在线程A上分配的内存应在线程A上释放,不要在线程B上释放线程A分配内存
RESULTTYPE CThreadSoap::CallMapBasicInfo( const HWND &hWnd,const char *lpcszMapService )
{
if( NULL == this->m_pthread_mutex || NULL == this->m_pthread_cond )
return ERR_INITIALIZE_FAIL;
if( NULL == lpcszMapService )
return ERR_INVALID_ARGUMENTS;
bool thread_is_run;
long thread_cur_action;
size_t dwMemSize( ( strlen(lpcszMapService) + 1 ) * sizeof(char) );
//检查线程的状态
this->CheckStatus(thread_is_run,thread_cur_action);
if( false == thread_is_run )
return ERRPT_THREAD_NOTRUN;
if( 0 != thread_cur_action )
return ERRPT_THREAD_ACTION;
::pthread_mutex_lock( &this->m_pthread_mutex );
//注意action动作在调用完成后自动还原
this->m_ActionInfo.hWnd = hWnd;
this->m_ActionInfo.action = PT_ACTION_WEBSERVICE_MAPBASICINFO;
this->m_ActionInfo.data.dwMemSize = dwMemSize;
this->m_ActionInfo.data.lpData = malloc( dwMemSize );
if( NULL == this->m_ActionInfo.data.lpData )
{
this->m_ActionInfo.action = 0;
this->m_ActionInfo.data.dwMemSize = 0;
::pthread_mutex_unlock(&this->m_pthread_mutex );
return ERR_MALLOC_FAIL;
}
memset(this->m_ActionInfo.data.lpData,0x0, dwMemSize);
strcpy_s((char *)this->m_ActionInfo.data.lpData, dwMemSize,lpcszMapService );
//等待线程获取参数完成后释放资源
::pthread_cond_wait( &this->m_pthread_cond, &this->m_pthread_mutex );
//释放资源
//线程状态保持到Soap方法调用完成后还原ResetThreadAction
//this->m_ActionInfo.hWnd = NULL;
//this->m_ActionInfo.action = 0;
this->m_ActionInfo.data.dwMemSize = 0;
free(this->m_ActionInfo.data.lpData);
this->m_ActionInfo.data.lpData = NULL;
::pthread_mutex_unlock(&this->m_pthread_mutex );
return RC_SUCCESS;
}
5.线程运行的方法内部不能直接使用类的成员变量,如果需要读写类成员变量,应通过互斥对象或读写锁对象,将类成员变量复制到方法中局部变量或将局部变量复制到类成员变量.注意是采用复制的方式,虽然效率稍差,但能保证线程安全.
6.pThread优先使用读写锁对象(pthread_rwlock_t),例如CallMapBasicInfo的返回成功用,用写锁(pthread_rwlock_wrlock)将返回值保存到共享区,获取时通过读锁(pthread_rwlock_rdlock)将共享区中的信息复制出来.