MFC全局函数AfxBeginThread 及其与CreateThread的区别

MFC全局函数AfxBeginThread 及其与CreateThread的区别

afxbeginthread   

createthread

函数功能描述:创建新的线程

函数原型:
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc/*线程函数地址*/,

                            LPVOID pParam/*线程参数*/,

                            int nPriority =THREAD_PRIORITY_NORMAL/*线程优先级*/,

                            UINT nStackSize = 0/*线程堆大小默认为1M*/,

                            DWORD dwCreateFlags = 0,

                            LPSECURITY_ATTRIBUTES
                            lpSecurityAttrs = NULL );

CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

返回值:
指向新创建的线程对象。

参数:
pfnThreadProc:工作线程的函数指针,不可以为空。并且工作线程的函数必须如此声明
               UINT MyControllingFunction( LPVOID pParam );
pThreadClass 从CWinThread类继承来的对象的RUNTIME_CLASS指针。
pParam:    传递给工作线程函数pfnThreadProc的参数
nPriority:  线程的优先级。如果为0,则与创建它的线程优先级相同。可以通过参考Win32 Programmer’s
               Reference中的SetThreadPriority得到所有可用的优先级列表和描述。

nStackSize:  以字节为单位指定新线程的堆栈大小。如果为0,则与创建它的线程的堆栈大小相同。

dwCreateFlags:指定一个额外的标志控制线程的产生。它可以包括下面两个值中的一个:CREATE_SUSPENDED:以挂起

                                模式开始线程并且指定挂起次数.当调用ResumeThread时,这个线程才会被执行。0:创建之后,马上执

                                行线程。lpSecurityAttrs:指向SECURITY_ATTRIBUTES结构的指针,结构中指定了线程的安全属性。如果为NULL,则与  
                 创建它的线程的安全属性相同。如果希望得到更多的有关SECURITY_ATTRIBUTES结构的信息
,  
                 请参考Win32 Programmer’s Reference。

注释:
调用这个函数创建一个新的线程。第一种形式的AfxBeginThread创建一个工作线程;第二种形式创建一个用户
接口线程。
AfxBeginThread创建一个新的CWinThread对象,调用它的CreateThread函数开始执行线程并且返回指向线程的指
针。Checks are made throughout the procedure to make sure all objects are deallocated properly
should any part of the creation fail. 终止线程,可以在线程函数中调用AfxEndThread, 或者从工作线程

的函数中返回。
了解更多的有关AfxBeginThread的信息,可以参考文章 Multithreading: Creating Worker Threads 和
Multithreading: Creating User-Interface Threads in Visual C++ Programmers Guide.
参看:
AfxGetThread
示例:

  创建一个工作线程:
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; //表示线程创建标志,为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* AfxBeginThread(
   CRuntimeClass* pThreadClass,
   int nPriority = THREAD_PRIORITY_NORMAL,
   UINT nStackSize = 0,
   DWORD dwCreateFlags = 0,
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

参数说明:
pfnThreadProc:线程函数的地址,该参数不能设置为NULL,线程函数必须定义成全局函数或者类的静态成员函数

例如:
UINT myThreadFunc(LPVOID lparam)
或者

class A
{
public:
        static UINT __stdcall myThreadFunc(LPVOID lparam);
}
之所以要定义成类的静态成员函数,是因为类的静态成员函数不属于某个类对象,这样在调用函数
的时候就不用传递一个额外的this指针.

pThreadClass:指向从CWinThread派生的子类对象的RUNTIME_CLASS

pParam:要传递给线程函数的参数

nPriority:要启动的线程的优先级,默认优先级为THREAD_PRIORITY_NORMAL(普通优先级),关于线程
 优先级的详细说明请参考Platform SDK SetThreadPriority函数说明

nStackSize:新线程的堆栈大小,如果设置为0,则使用默认大小,在应用程序中一般情况下线程的默认堆栈大小
 1M 

dwCreateFlags:线程创建标志,该参数可以指定为下列标志
 CREATE_SUSPENDED:以挂起方式启动线程,如果你在线程启动之前想初始化一些CWinThread类中的一些成员变量
 比如:m_bAutoDelete或者你的派生类中的成员变量,当初始化完成之后,你可以使用CWinThread类的ResumeThread
 成员函数来恢复线程的运行

 如果把该标志设置为0,则表示立即启动线程
lpSecurityAttrs:指向安全描述符的指针,如果使用默认的安全级别只要讲该参数设置为NULL就可以了!

上面就是AfxBeginThread函数的简单说明,我们在使用的时候一般情况下只要指定前两个参数,其他
参数使用默认值就可以.嗯,的确,使用起来是很简单,只要这个函数一被调用,就创建了一个线程.
但是大家有没有想过,AfxBeginThread函数究竟是如何启动的线程呢?它的内部是如何实现的呢?

下面我们就来看一下AfxBeginThread函数的内部实现

//启动worker线程
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
 int nPriority, UINT nStackSize, DWORD dwCreateFlags,
 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
#ifndef _MT
         pfnThreadProc;
         pParam;
         nPriority;
         nStackSize;
         dwCreateFlags;
         lpSecurityAttrs;

         return NULL;
#else
         ASSERT(pfnThreadProc != NULL);

         CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
         ASSERT_VALID(pThread);

         if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
                  lpSecurityAttrs))
         {
                  pThread->Delete();
                  return NULL;
         }
         VERIFY(pThread->SetThreadPriority(nPriority));
         if (!(dwCreateFlags & CREATE_SUSPENDED))
                  VERIFY(pThread->ResumeThread() != (DWORD)-1);

         return pThread;
#endif //!_MT)
}

//启动UI线程
CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,
 int nPriority, UINT nStackSize, DWORD dwCreateFlags,
 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
#ifndef _MT
        pThreadClass;
        nPriority;
        nStackSize;
        dwCreateFlags;
        lpSecurityAttrs;

        return NULL;
#else
        ASSERT(pThreadClass != NULL);
        ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread)));

        CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
        if (pThread == NULL)
                AfxThrowMemoryException();
        ASSERT_VALID(pThread);

        pThread->m_pThreadParams = NULL;
        if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
                lpSecurityAttrs))
        {
                pThread->Delete();
                return NULL;
        }
        VERIFY(pThread->SetThreadPriority(nPriority));
        if (!(dwCreateFlags & CREATE_SUSPENDED))
                VERIFY(pThread->ResumeThread() != (DWORD)-1);

        return pThread;
#endif //!_MT
}

从上面的代码中可以看出AfxBeginThread所做的事情主要有以下几点:

1.在heap中配置一个新的CWinThread对象(worker线程)
代码如
:CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
调用CRuntimeClass结构中的CreateObject函数创建CWinThread对象

CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
CRuntimeClass
以及MFC相关类的内部实现,详情请参考
《深入浅出MFC》侯捷著

2.调用CWinThread::CreateThread()并设定属性,使线程以挂起状态产生
pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,lpSecurityAttrs);

3.设定线程的优先权
pThread->SetThreadPriority(nPriority);

4.调用CWinThread::ResumeThread
pThread->ResumeThread();

 

 AfxBeginThread和CreateThread具体区别

        具体说来,CreateThread这个 函数是windows提供给用户的 API函数,是SDK的标准形式,在使用的过程中要考虑到进程的同步与互斥的关系,进程间的同步互斥等一系列会导致操作系统死锁的因素,用起来比较繁琐一些,初学的人在用到的时候可能会产生不可预料的错误,建议多使用AfxBeginThread,是编译器对原来的CreateThread函数的封装,用与MFC编程(当然,只要修改了项目属性,console和win32项目都能调用)而_beginthread是C的运行库函数。

在使用AfxBeginThread时,线程函数的定义为:

UINT   _yourThreadFun(LPVOID   pParam);参数必须如此

在使用CreateThread时,线程的函数定义为: 

DWORD  WINAPI  _yourThreadFun(LPVOID pParameter);

        两个的实质都是一样的,不过AfxBeginThread返回一个CWinThread的指针,就是说他会new一个CWinThread对象,而且这个对象是自动删除的(在线程运行结束时),给我们带来的不便就是无法获得它的状态,因为随时都有可能这个指针指向的是一个已经无效的内存区域,所以使用时(如果需要了解它的运行状况的话)首先CREATE_SUSPENDED让他挂起,然后m_bAutoDelete=FALSE,接着才ResumeThread,最后不要了delete那个指针。     CreatThread就方便多了,它返回的是一个句柄,如果你不使用CloseHandle的话就可以通过他安全的了解线程状态,最后不要的时候CloseHandle,Windows才会释放资源,所以我一般使用CreatThread,方便。

如果用MFC编程,不要用CreateThread,如果只是使用Runtime Library,用_BegingThread,总之,不要轻易使用CreateThread。这是因为在MFC和RTL中的函数有可能会用到些它们所封装的公用变量,也就是说AfxBeginThread和_BeginThread都有自己的启动代码是CreateThread所没有的。在用CreateThread所创建的线程中使用MFC的类和RTL函数就有可能出现问题。如果你是用汇编编写win32程序并且在线程函数中也不调用MFC和RTL的函数,那用CreateThread就没问题,或者你虽然是用C写线程函数,但你很小心没调用RTL函数也不会有问题。

  CreateThread是由操作系统提供的接口,而AfxBeginThread和_BeginThread则是编译器对它的封装。

  在可能的情况下,不要调用_beginthread,而应该调用_beginthreadex。以及对应的_endthreadex。这都是C++运行期函数。但是使用_beginthread,无法创建带有安全属性的新线程,无法创建暂停的线程,也无法获得线程ID,_endthread的情况类似,它不带参数,


  这意味这线程的退出代码必须硬编码为0。这两个函数在_beginthreadex和_endthreadex中进行调用。CreateThread不要进行直接调用。 

简言之:

  AfxBeginThread是MFC的全局函数,是对CreateThread的封装。

    CreateThread是Win32 API函数,前者最终要调到后者。



1>.
具体说来,CreateThread这个 函数是windows提供给用户的 API函数,是SDK的标准形式,在使用的过

程中要考虑到进程的同步与互斥的关系,进程间的同步互斥等一系列会导致操作系统死锁的因素,用起来

比较繁琐一些,初学的人在用到的时候可能会产生不可预料的错误,建议多使用AfxBeginThread,是编译

器对原来的CreateThread函数的封装,用与MFC编程(当然,只要修改了项目属性,console和win32项目

都能调用)而_beginthread是C的运行库函数。

2>
在使用AfxBeginThread时
线程函数的定义为:UINT   _yourThreadFun(LPVOID   pParam)参数必须如此

在使用CreateThread时,
线程的函数定义为: DWORD WINAPI _yourThreadFun(LPVOID pParameter)

两者实质是一样的,
不过AfxBeginThread返回CWinThread指针,就是说它会new一个CWinThread对象,而这个对象在线程运行结束时是会自动删除的,

CreatThread,它返回的是一个句柄,如果你不使用CloseHandle的话就可以通过它安全的了解线程状态,

最后不要的时候CloseHandle,Windows才会释放资源

你可能感兴趣的:(MFC,mfc,函数,线程)