AfxBeginThread
UINT playThread(LPVOID pParam){ //播放线程,固定格式
//......做变量声明,赋值等前期工作
while(SomeCondition){
//播放线程的循环
//......播放音乐,不解析
}
return
0;
}
void CPlayerDlg::OnBnClickedPlay(){
//播放按钮响应函数
if(isThreadPause){
//判断是否暂停中
isThreadPause=false;
pPlayerThread->ResumeThread();//继续播放
}
else{
OnBnClickedStop();
pPlayerThread=AfxBeginThread(playWaveThread,NULL); //开启播放线程
}
}
void
CPlayerDlg::OnBnClickedPause(){
//暂停响应函数
if(!isThreadPause){
PlayerThread->SuspendThread();
//挂起进程,相当于暂停播放
isThreadPause=true;
}
}
void
CPlayerDlg::OnBnClickedStop(){ //终止响应函数
if(pPlayThread){
isThreadPause=false;
TerminateThread(pPlayerThread->m_hThread,0);//强行终止线程,这里有问题,后面说
}
}
其中播放线程playThread的声明是固定那种格式的,而且最好写成全局函数,方便,如果写成类成员函数的话又要加static,调用时又要加作用域的,十分蛋痛。写完后果断运行,yeah,能播放、暂停和停止,相当舒服,也没去理会细节的问题。
看看程序内存占用情况,发现了一个狠严重的问题:每当我停止一首歌,播放下一首时,内存就突然间往上跳。一开始以为是正常的内存创建和回收造成的浮动,但我继续不断地重复播放停止、播放停止,发现内存一直往上升。虽然每次都只是上升一点点,但明摆着的memory leak搁在那,还不搞它哥以后怎样出来混?
问题出在TerminateThread这个函数。这个TerminateThread结束线程用的是相当暴力的方法,据说连里面的局部变量都不释放。
停止的响应函数里用::PostThreadMessage(由于播放线程是全局函数,所以前面要加::)给播放线程发送停止消息,播放线程里加一个MSG的变量和while,每次里面调用PeekMessage来检查是否发来停止的消息,写了下,代码相当简练明了:
#define
WM_THREAD_STOP 0x0427 //自定义一个消息,也可以用系统定义的如WM_QUIT
UINT
playWaveThread(LPVOID
pParam){ //......做变量声明,赋值等前期工作
while(SomeCondition){
//播放线程的循环
MSG msg;
//增加一个MSG的变量msg来接收消息
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ //将消息队列里的消息逐个读入msg
if(msg.message==WM_THREAD_STOP){
//如果收到终止消息则退出
//TODO:放在堆里的变量要在这里手动清理
return
0; //线程正常返回,会释放局部变量等内存资源
}
else{
DispatchMessage(&msg);//字面意思,不解释
}
}
//......播放音乐,不解析
}
return 0;//正常播放结束,释放资源
}
void
CPlayerDlg::OnBnClickedPlay(){……}//播放按钮响应函数,不变
void
CPlayerDlg::OnBnClickedPause(){……}//暂停响应函数,也不变
void
CPlayerDlg::OnBnClickedStop(){
if(pPlayerThread){
isThreadPause=false;
//原来的TerminateThread不用,换成下面这个
::PostThreadMessage(pPlayerThread->m_nThreadID,WM_THREAD_STOP,0,0);
}
}
UINT nStackSize = 0, //以字节为单位指定新线程的堆栈大小。如果为0,则与创建它的线程的堆栈大小相同。 DWORD dwCreateFlags = 0, //指定一个额外的标志控制线程的产生。 LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL //向SECURITY_ATTRIBUTES结构的指针,结构中指定了线程的安全属性。如果为NULL,则与
创建它的线程的安全属性相同。);
第一种形式的AfxBeginThread创建一个工作线程;第二种形式创建一个用户接口线程(用于创建工作者线程)。
返回值: 一个指向新线程的线程对象AfxBeginThread创建一个新的CWinThread对象,调用它的CreateThread函数开始执行线程并且返回指向线程的指针。结束线程的两种方式
1 : 这是最简单的方式,也就是让线程函数执行完成,此时线程正常结束.它会返回一个值,一般0是成功结束,
当然你可以定义自己的认为合适的值来代表线程成功执行.在线程内调用AfxEndThread将会直接结束线程,此时线
程的一切资源都会被回收.
2 : 如果你想让别一个线程B来结束线程A,那么,你就需要在这两个线程中传递信息.
不管是工作者线程还是界面线程,如果你想在线程结束后得到它的确结果,那么你可以调用:
::GetExitCodeThread函数
例:
创建一个工作线程:
UINT WorkForce(LPVOID lpParameter);//线程函数声明
CWinThread *pMyFirstWorker,*pMySecondWorker;
LPVOID pParam = NULL;
int nPriority = THREAD_PRIORITY_ABOVE_NORMAL;//默认为THREAD_PRIORITY_NORMAL
UINT nStackSize = 0;//与创建它的线程堆栈大小相同
DWORD dwCreateFlags = 0;//创建后立即执行
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ;//与创建它的线程安全属性相同
pMyFirstWorker=AfxBeginThread( (AFX_THREADPROC)WorkForce, pParam, nPriority , nStackSize,dwCreateFlags , lpSecurityAttrs);
pMySecondWorker=AfxBeginThread( (AFX_THREADPROC)WorkForce, pParam);//如果采用默认值
DWORD WINAPI WorkForce( LPVOID lpParameter // 线程所需参数,可以通过它传递数据)
{
return 0;//什么不做
}
CWinThread* MyThread=AfxBeginThread(MyThreadFunction , pParam , THREAD_PRIORITY_NORMAL , 0 , 0 , NULL);
线程的等待与唤醒
(1)让线程等待(暂时挂起):
MyThread->SuspendThread();
(2)唤醒暂停的线程:
MyThread->ResumeThread();
查看线程状态:
DWORD code;
GetExitCodeThread(MyThread->m_hThread , &code);
if(code==STILL_ACTIVE){//线程仍在执行}
else {//线程停止执行}
一个线程给另一个线程发送消息:PostThreadMessage()