zoukankan      html  css  js  c++  java
  • Win32 多线程的创建方法和基本使用

    Win32多线程的创建方法主要有:

    (1)CreateThread()

    (2)_beginthread()&&_beginthreadex()

    (3)AfxBeginThread()

    (4)CWinThread类

    (1)CreateThread()

    百度百科:http://baike.baidu.com/view/1191444.htm

    函数原型:

    view plaincopy to clipboardprint?
    01.HANDLE CreateThread(
    02.  LPSECURITY_ATTRIBUTES lpThreadAttributes,
    03.  DWORD dwStackSize,
    04.  LPTHREAD_START_ROUTINE lpStartAddress,
    05.  LPVOID lpParameter,
    06.  DWORD dwCreationFlags,
    07.  LPDWORD lpThreadId);
    08.}
    HANDLE CreateThread(
      LPSECURITY_ATTRIBUTES lpThreadAttributes,
      DWORD dwStackSize,
      LPTHREAD_START_ROUTINE lpStartAddress,
      LPVOID lpParameter,
      DWORD dwCreationFlags,
      LPDWORD lpThreadId);
    }

    头文件:Windows.h

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

    参数简要说明:

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

    创建线程的代码:

    view plaincopy to clipboardprint?
    01.#include "stdafx.h"
    02.#include
    03.
    04.DWORD WINAPI ThreadProc(LPVOID lpParam)
    05.{
    06. printf("sub thread started ");
    07. printf("sub thread finished ");
    08. return 0;
    09.}
    10.
    11.int main(int argc, char* argv[])
    12.{
    13. DWORD threadID;
    14. HANDLE hThread;
    15. hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程
    16.
    17. return 0;
    18.}
    #include "stdafx.h"
    #include

    DWORD WINAPI ThreadProc(LPVOID lpParam)
    {
    printf("sub thread started ");
    printf("sub thread finished ");
    return 0;
    }

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

    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的例子:

    view plaincopy to clipboardprint?
    01.#include "stdafx.h"
    02.#include
    03.
    04.DWORD WINAPI ThreadProc(LPVOID lpParam)
    05.{
    06. printf("sub thread started ");
    07. // TODO: Add your thread code here.
    08. printf("sub thread finished ");
    09. return 0;
    10.}
    11.
    12.int main(int argc, char* argv[])
    13.{
    14. DWORD threadID;
    15. HANDLE hThread;
    16. hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程
    17.
    18. WaitForSingleObject(hThread,INFINITE);
    19. CloseHandle(hThread); // 关闭内核对象
    20.
    21. return 0;
    22.}
    #include "stdafx.h"
    #include

    DWORD WINAPI ThreadProc(LPVOID lpParam)
    {
    printf("sub thread started ");
    // TODO: Add your thread code here.
    printf("sub thread finished ");
    return 0;
    }

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

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

    return 0;
    }
    (2)_beginthread()&&_beginthreadex()

    百度百科:http://baike.baidu.com/view/3029167.htm

    MSDN:http://msdn.microsoft.com/zh-cn/library/kdzttdcb.aspx

    函数原型:

    view plaincopy to clipboardprint?
    01.uintptr_t _beginthread( // NATIVE CODE
    02. void( __cdecl *start_address )( void * ),
    03. unsigned stack_size,
    04. void *arglist
    05.);
    uintptr_t _beginthread( // NATIVE CODE
    void( __cdecl *start_address )( void * ),
    unsigned stack_size,
    void *arglist
    );

    头文件:process.h

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

    下面是一个使用_beginthread()的基本的例子:

    view plaincopy to clipboardprint?
    #include "stdafx.h"
    #include
    #include

    void __cdecl ThreadProc(void *para)
    {
     printf("sub thread started ");
     // TODO: Add your thread code here.
     printf("sub thread finished ");
    _endthread(); // 可以省略,隐含会调用。
    }

    int main(int argc, char* argv[])
    {
    HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);

    WaitForSingleObject(hThread,INFINITE);
     CloseHandle(hThread);
    }
    #include "stdafx.h"
    #include
    #include

    void __cdecl ThreadProc(void *para)
    {
    printf("sub thread started ");
    // TODO: Add your thread code here.
    printf("sub thread finished ");
    _endthread(); // 可以省略,隐含会调用。
    }

    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创建线程,否则会内存泄漏“的来源了。

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

    Related Topics:http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html http://www.cnblogs.com/whiteyun/archive/2011/06/02/2067742.html ....

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

    2. 并不是所有的使用CreateThread的情况都会有内存泄漏。看了很多人的文章,只有http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html的分析是最清晰的,我已经转到http://dl.dbank.com/c03ljl2iud了,可下载查看(版权归原作者所有)。

    总之,建议是使用_beginthread取代CreateThread来创建线程。

    (3)AfxBeginThread():

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

    (4)CWinThread类:

    很显然,是MFC中创建线程的类,同上,不多说了。

    欢迎补充!

    (1)补充内容:

    关于WaitForMultipleObjects在_beginthread无法使用的问题

    问题:使用_beginthread创建多个线程,无法使用WaitForMultipleObjects来进行同步。

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

    view plaincopy to clipboardprint?
    01.#include "stdafx.h"
    02.#include
    03.#include
    04.
    05.void __cdecl ThreadProc(void *para)
    06.{
    07. printf("sub thread started ");
    08. // TODO: Add your thread code here.
    09. printf("sub thread finished ");
    10. _endthread(); // 可以省略,隐含会调用。
    11.}
    12.
    13.int main(int argc, char* argv[])
    14.{
    15. DWORD threadID;
    16. HANDLE hThread[10];
    17. for(int i =0;i<10;i++)
    18. hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL);
    19.
    20. WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //无法同步所有线程!
    21. for(int i = 0;i<10;i++) {
    22. CloseHandle(hThread);
    23. }
    24.}
    #include "stdafx.h"
    #include
    #include

    void __cdecl ThreadProc(void *para)
    {
    printf("sub thread started ");
    // TODO: Add your thread code here.
    printf("sub thread finished ");
    _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);
    }
    }
    期望的结果是程序能输出10次的线程创建结束的消息,但是实际运行发现,无法达到这么多次数。为何?这是因为WaitForMultipleObjects在这里无法正常工作。原因是:

    _endthread()在结束线程的时候,会自动调用CloseHandle关闭内核对象。这就容易解释了,如果提前关闭了内核对象,WaitForMultipleObjects会返回错误。那么有没有专门用于_beginthread创建的线程的同步方法呢,就我目前所知,好象是没有的!要解决这里的问题,可以分别调用WaitForSingleObject来同步,当然,使用其他一些变相的方法也是可以的,另外,上面的CloseHandle当然就可以不用再调用了。

    总结:看来_beginthread也不是那么好用。:)
  • 相关阅读:
    Java 中位移运算符 >>,>>>,<<
    HashMap 源码解读
    CentOS 配置防火墙操作实例(启、停、开、闭端口)
    CentOS 配置防火墙操作实例(启、停、开、闭端口)
    js实现页面重新加载
    js实现页面重新加载
    关于Ajax的技术组成与核心原理
    关于Ajax的技术组成与核心原理
    PHP水印制作
    PHP水印制作
  • 原文地址:https://www.cnblogs.com/logy/p/3311752.html
Copyright © 2011-2022 走看看