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);
           }
}

CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, //工作线程的函数指针,不可以为空。
         LPVOID pParam, //传递给工作线程函数pfnThreadProc的参数。
         int nPriority = THREAD_PRIORITY_NORMAL, //线程的优先级。如果为0,则与创建它的线程优先级相同。
         UINT nStackSize = 0,  //以字节为单位指定新线程的堆栈大小。如果为0,则与创建它的线程的堆栈大小相同。
         DWORD dwCreateFlags = 0, //指定一个额外的标志控制线程的产生。
         LPSECURITY_ATTRIBUTES   lpSecurityAttrs = NULL//
);
工作线程的函数必须如此声明:UINT MyControllingFunction( LPVOID pParam );
 
CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass,//从CWinThread类继承来的对象的RUNTIME_CLASS指针。
         int nPriority = THREAD_PRIORITY_NORMAL,  //线程的优先级。如果为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()

 

posted @ 2012-05-09 22:28  血马雄风  阅读(2444)  评论(1)    收藏  举报