Win32 多线程的创建方法和基本使用

Win32 多线程的创建方法和基本使用 dedecms.com


  本文主要总结了Win32提供的创建多线程相关的API接口和基本的使用框架。
  Win32多线程的创建方法主要有:

织梦内容管理系统

  (1)CreateThread()
  (2)_beginthread()&&_beginthreadex()
  (3)AfxBeginThread()
  (4)CWinThread类 织梦好,好织梦

////////////////////////////////////////////////////////////////////////////

织梦好,好织梦

  (1)CreateThread()

内容来自dedecms

  函数原型:

织梦好,好织梦

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  DWORD dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId); copyright dedecms

  头文件:Windows.h dedecms.com

  CreateThread是Win32提供的创建线程的最基础的API,用于在主线程上创建一个线程。返回一个HANDLE句柄(内核对象)。 copyright dedecms

  参数简要说明:
  lpThreadAttributes:线程属性,用于设置线程的属性,NULL表示使用默认的设置。
  dwStackSize:线程堆栈大小,使用0采用默认设置,windows会根据需要动态增加堆栈大小。
  lpStartAddress:指向线程函数的指针。
  lpParameter:向线程函数传递的参数。
  dwCreationFlags:线程标志,CREATE_SUSPENDED表示创建一个挂起的线程,0表示创建后立即激活线程。
  lpThreadId,先线程的ID(输出参数)。 内容来自dedecms

创建线程的代码:
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h" 织梦内容管理系统

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
    printf("子线程开始\n");
    printf("子线程结束\n");
    return 0;
} dedecms.com

int main(int argc, char* argv[])
{
    DWORD threadID;
    HANDLE hThread;
    hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程

copyright dedecms

    return 0;
}
////////////////////////////////////////////////////////////////////////////
  如果直接使用上面的代码,那么很可能没有任何输出,这是由于主线程创建了子线程后主线程继续向下运行,子线程还没来得及执行里面的代码主线程可能就结束了。这就需要另一个API来进行同步:WaitForSingleObject()。
  与之对应的还有WaitForMultipleObjects,用于同步一组内核对象。(参考http://msdn.microsoft.com/zh-cn/site/ms686360获取所有的同步函数(Synchronization Functions)的使用。
  WaitForSingleObject原型:DWORD WINAPI WaitForSingleObject(__in HANDLE hHandle, __in DWORD dwMilliseconds);其中,第一个参数是要等待的内核对象的句柄,第二个参数是设置等待超时时间,可以设置为INFINITE,表示一直等待直到有信号触发。
  在内核对象使用完毕后,一般需要关闭,使用CloseHandle()函数,参数为内核对象句柄。
  所以,以下是一个最基本的使用CreateThread的例子: 本文来自织梦

////////////////////////////////////////////////////////////////////////////
#include "stdafx.h" dedecms.com

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
    printf("子线程开始\n");
    // TODO: 在这儿添加你的线程代码
    printf("子线程结束\n");
    return 0;
}

copyright dedecms

int main(int argc, char* argv[])
{
    DWORD threadID;
    HANDLE hThread;
    hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程 织梦内容管理系统

    WaitForSingleObject(hThread,INFINITE);
    CloseHandle(hThread); // 关闭内核对象 copyright dedecms

    return 0;
}
////////////////////////////////////////////////////////////////////////////

织梦好,好织梦

    (2)_beginthread()&&_beginthreadex() 织梦内容管理系统

    函数原型:

织梦内容管理系统

uintptr_t _beginthread( // NATIVE CODE
    void( __cdecl *start_address )( void * ),
    unsigned stack_size,
    void *arglist
);

dedecms.com

  头文件:process.h dedecms.com

  参数说明:第一个参数是线程函数的指针,第二个参数是堆栈大小,第三个参数是要传递给线程函数的参数列表。返回值也是线程句柄(关于更多说明,参考MSDN)。
  同样,对于_beginthread()的同步,和CreateThread一样可以使用WaitForSingleObject函数,CloseHandle()关闭内核对象。另外,_beginthread()的线程函数是无返回值类型的,可以使用_endthread()在线程函数中结束线程。
  下面是一个使用_beginthread()的基本的例子:
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

dedecms.com

void __cdecl ThreadProc(void *para)
{
    printf("子线程开始\n");
    // TODO: 在这儿添加你的线程代码
    printf("子线程结束\n");
    _endthread(); // 可以省略,隐含会调用。
} 内容来自dedecms

int main(int argc, char* argv[])
{
    HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);
    WaitForSingleObject(hThread,INFINITE);
    CloseHandle(hThread);
} 本文来自织梦

  另外,还有一个函数_beginthreadex(),可以简单的认为_beginthread()为其简化版,所以更多的时候是使用更简单的_beginthread()了。
  说明:在MSDN中可以看到一句很重要的提示,内容为“For an executable file linked with Libcmt.lib, do not call the Win32 ExitThread API; this prevents the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.”,简单翻译就是说,对于链接Libcmt.lib的可执行程序,不要使用Win32的线程退出函数(ExitThread),这会阻止运行时系统回收分配的资源,应该使用_endthread,它能回收分配的线程资源然后调用ExitThread。这个问题看似没有提到CreateThread(),但是其实有关,这就是经常看到有些资料上坚决的说到”不要使用CreateThread创建线程,否则会内存泄漏“的来源了。

dedecms.com

  问题引出:CreateThread的内存泄漏问题(CreateThread和_beginthread的区别) copyright dedecms

  1. _beginthread也是通过CreateThread来创建线程的,只是_beginthread对其进行了一些封装,将相关”资源“通过线程的本地存储(TLS)传递给了线程函数的参数,然后在调用_endthread的时候,会将这些保存的资源进行释放。
  2. 并不是所有的使用CreateThread的情况都会有内存泄漏。

织梦好,好织梦

  总之,建议是使用_beginthread取代CreateThread来创建线程。 本文来自织梦

////////////////////////////////////////////////////////////////////////////

本文来自织梦

  (3)AfxBeginThread(): dedecms.com

  很显然,这是MFC中的Afx系列函数,一个在MFC中创建线程的全局函数。由于现在也不怎么用MFC了,这里就不多说了。

本文来自织梦

//////////////////////////////////////////////////////////////////////////// copyright dedecms

  (4)CWinThread类: 本文来自织梦

  很显然,是MFC中创建线程的类,同上,不多说了。
  欢迎补充! copyright dedecms

////////////////////////////////////////////////////////////////////////////
(1)补充内容: copyright dedecms

  关于WaitForMultipleObjects在_beginthread无法使用的问题
  问题:使用_beginthread创建多个线程,无法使用WaitForMultipleObjects来进行同步。 本文来自织梦

  这个问题可以用下面的例子来测试: copyright dedecms

#include "stdafx.h"

内容来自dedecms

void __cdecl ThreadProc(void *para)
{
    printf("子线程开始\n");
    // TODO: 在这儿添加你的线程代码
    printf("子线程结束\n");
    _endthread(); // 可以省略,隐含会调用。
}

织梦内容管理系统

int main(int argc, char* argv[])
{
    DWORD threadID;
    HANDLE hThread[10];
    for(int i =0;i<10;i++)
    hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL); 织梦好,好织梦

    WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //无法同步所有线程!
    for(int i = 0;i<10;i++) {
        CloseHandle(hThread);
    }
} 内容来自dedecms

  期望的结果是程序能输出10次的线程创建结束的消息,但是实际运行发现,无法达到这么多次数。为何?这是因为WaitForMultipleObjects在这里无法正常工作。原因是:
  _endthread()在结束线程的时候,会自动调用CloseHandle关闭内核对象。这就容易解释了,如果提前关闭了内核对象,WaitForMultipleObjects会返回错误。那么有没有专门用于_beginthread创建的线程的同步方法呢,就我目前所知,好象是没有的!要解决这里的问题,可以分别调用WaitForSingleObject来同步,当然,使用其他一些变相的方法也是可以的,另外,上面的CloseHandle当然就可以不用再调用了。
  总结:看来_beginthread也不是那么好用。:)

copyright dedecms