begingthread afxbeginthread createthread

转载 2015年07月06日 20:08:44

在微软的 Programming Techniques 说明文件中有一句看似悲惨的警告:

警告:如果你在一个与 LIBCMT.LIB 链接的程序中调用 C runtime 函数, 你的线程就必须以 _beginthread() 启动之。不要使用 Win32 的ExitThread() 和 CreateThread()。

 

首先看一下_beginthreadex:

1、如果你写一个多线程程序,而且没有使用MFC,那么你应该总是和多线程版本的C Run time library进行链接。并且应该总是以_beginthreadex和_endthreadex取代createthread和exitthread。_beginthread参数与createthread一致并且对C Runtime library进行了必要的初始化。

2、关于C Runtime library的多线程版本:之前的版本不能被多线程的应用程序所使用。由于它使用了很多全局变量以及静态变量,所以在多线程应用程序中很容易产生同步错误。因为这个原因,所以产生了C Runtime library的多线程版本。

3、你可以将_beginthreadex理解为createthread的外包函数,它记录了一些和启动线程相关的信息。

4、unsigned long _beginthreadex(   

void *security,  //安全属性

unsigned stack_size,  //堆栈大小 

unsigned (__stdcall *start_address)(void *),  //回调函数   

void *arglist,unsigned initflag,  //创建标志  

unsigned* thrdaddr  //线程ID

);

 

一个简单的例子:

#include <iostream>
#include <cstdlib>
using namespace std;
#include <Windows.h>
#include <process.h>

 

unsigned _stdcall ThreadProc(void* param);

int main()
{
 HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, NULL, NULL, NULL);
 if (handle == NULL)
 {
  cout<<"create thread failed"<<endl;
  system("pause");
  return 0;
 }
 WaitForSingleObject(handle, INFINITE);
 CloseHandle(handle);
 system("pause");
 return 0;
}

unsigned _stdcall ThreadProc(void* param)
{
 cout<<"_beginthreadex create thread"<<endl;
 return 0;
}

 

如果一个多线程程序在worker线程中不会调用c runtime library多线程版本中函数的话,应该能够使用单线程版本的c runtime library并且可以通过createthread和exitthread来创建和结束线程。然而C程序不调用任何多线程版本的c runtime函数通常是不可能的,所以记住这一点:如果要产生一个多线程的C程序(不使用MFC),那么请一定使用_beginthreadex和_endthreadex,而不要使用createthread和_beginthread。

关于_beginthread:它被认为是一个头脑简单的函数,它并没有获得和createthread函数完全一样的参数,所以有些事情它办不到,比如说线程的挂起状态。另外重要的一点是,它所产生出来的线程所做的第一件事情就是关闭掉handle,所以由它所返回的handle可能可用,也可能不可用。



<<Windows核心编程>>中有很详细地介绍。我再说一些吧
_beginthreadex是微软的C/C++运行时库函数,CreateThread是操作系统的函数。
_beginthreadex通过调用CreateThread来实现的,但比CreateThread多做了许多工作。
注意:若要创建一个新线程,绝对不要使用CreateThread,而应使用_beginthreadex.
Why?考虑标准C运行时库的一些变量和函数,如errno,这是一个全局变量。全局变量用于
多线程会出什么事,你一定知道的了。故必须存在一种机制,使得每个线程能够引用它自己的
errno变量,又不触及另一线程的errno变量._beginthreadex就为每个线程分配自己的
tiddata内存结构。该结构保存了许多像errno这样的变量和函数的值、地址(自己看去吧)。
通过线程局部存储将tiddata与线程联系起来。具体实现在Threadex.c中有。
结束线程使用函数_endthreadex函数,释放掉线程的tiddata数据块。



4.线程:资源调度的最小单位
  线程的构成:
    (1)内核对象:存放线程相关信息
    (2)线程堆栈:维护执行代码时所需的参数和变量
  通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。在引入线程的操作系统中,通常把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。
 
下面看看C++创建进程的相关函数:
复制代码
1 HANDLE WINAPI CreateThread(
2   __in          LPSECURITY_ATTRIBUTES lpThreadAttributes,
3   __in          SIZE_T dwStackSize,
4   __in          LPTHREAD_START_ROUTINE lpStartAddress,
5   __in          LPVOID lpParameter,
6   __in          DWORD dwCreationFlags,
7   __out         LPDWORD lpThreadId
8 );
复制代码
复制代码
1 uintptr_t _beginthreadex( 
2    void *security,
3    unsigned stack_size,
4    unsigned ( *start_address )( void * ),
5    void *arglist,
6    unsigned initflag,
7    unsigned *thrdaddr 
8 );
复制代码

两个函数都是用于创建线程,第一个是Windows API函数,在WinBase.h头文件中,第二个不是API函数,在process.h头文件中
参数说明:

1.线程安全性:表示是否可以被子进程所继承

2.初始堆栈大小:如果为0或者小于默认值,则使用和调用线程同样大小的空间

3.线程其实地址:一个函数指针,指向线程函数

4.参数:传递给线程函数的参数

5.创建选项:如果为CREATE_SUSPENDED表示创建后挂起,如果为0表示创建后立即执行

6.线程ID

两个函数的区别:

  malloc、fopen、ctime等函数需要专门的线程局部存储数据块,这个数据块在创建线程时创建。如果用CreateThread,则不会创建,这样,函数能够正常使用,但是会自动创建数据块,但是函数并不会释放创建的数据库,所以并不会将其删除,就导致内存泄露!!!

  而_beginthreadex(内部也调用CreateThread)和_beginthreadex(会自动调用CloseHandle关闭句柄)对这个内存块做了处理。

 

代码演示:

复制代码
 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <process.h>
 4 using namespace std;
 5 
 6 
 7 DWORD WINAPI CreateFun(LPVOID lParam)
 8 {
 9     cout << "CreateThread" << endl;
10     return 0;//0表示成功
11 
12 }
13 
14 UINT _stdcall beginFun(LPVOID lParam)
15 {
16     cout << "beginthreadex" << endl;
17     return 0;
18 }
19 int main(void)
20 {
21 
22     DWORD dwID;
23     UINT nID;
24     HANDLE hC;
25     HANDLE hB;
26 
27     hC = CreateThread(NULL, 0, CreateFun, NULL, 0, &dwID);
28 
29     if (NULL != hC)
30     {
31         CloseHandle(hC);
32     }
33 
34 
35 
36     hB = (HANDLE)_beginthreadex(NULL, 0, beginFun, NULL, 0, &nID);
37     if (NULL != hB)
38     {
39         CloseHandle(hB);
40     }
41 
42     Sleep(1000);
43 }
复制代码

 

 CloseHandle:关闭句柄

  调用CloseHandle并不会终止线程的执行,而是递减线程内核对象句柄计数,线程执行完毕后也会自动递减,当计数为0时释放线程内核对象。当进程终止时也会清理内核对象。

但是,如果不关闭,可能导致有些进程拥有的资源无法释放,导致内存泄露。

线程的相关函数:

(1)CreateThread:创建线程,失败返回NULL,成功返回线程句柄

(2)SuspendThread:挂起线程

(3)ResumeThread:恢复线程

(4)OpenThread:打开线程,根据线程ID得到线程句柄

(5)ExitThread:退出线程

(6)TerminateThread:终止线程

(7)GetExitCodeThread:获取线程运行状态,如果为STILL_ALIVE表示正在运行。

(8)GetCurrentThread:获取当前线程句柄

(9)GetCurentThreadID:获取当前线程ID

 注意:最好不要显式的调用ExitThread和TerminateThread,因为可能导致线程无法清理某些东西,导致内存泄露~


CreateThread 创建线程所引起的内存泄漏的问题

内存泄漏编辑 在很多参考书上,都说不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,因为这样做会导致内存泄漏,而应该用_beginthread来创建线程,_en...
  • hkwlg1314
  • hkwlg1314
  • 2015年10月26日 21:19
  • 1117

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

MFC全局函数AfxBeginThread 及其与CreateThread的区别 afxbeginthread    createthread 函数功能描述:创建新的线程 函数原型: ...
  • xiaohuihui52309
  • xiaohuihui52309
  • 2016年08月19日 12:09
  • 129

AfxBeginThread如何安全退出

之前的想法是,如果尽量不要在线程中分配内存,这样当线程没有正常退出时,很容易就出现内存泄漏的情况。 所以在这里的test代码也是如此,没有在线程中分配内存,而是在主线程中分配的内存供线程使用。  ...
  • qiaoquan3
  • qiaoquan3
  • 2017年02月21日 12:54
  • 625

MFC之AfxbeginThread 线程 创建、挂起、释放、结束、退出

MFC之AfxbeginThread创建线程 本文简单阐述了如何使用一个afxbeginthread创建一个线程(两种方法,使用默认设置,使用自主设置参数),以及一些如同,挂起,释放。边界锁等操作。 ...
  • i_likechard
  • i_likechard
  • 2016年11月25日 12:12
  • 7571

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

MFC全局函数AfxBeginThread 及其与CreateThread的区别 afxbeginthread    createthread 函数功能描述:创建新的线程 函数原型: CWin...
  • bytxl
  • bytxl
  • 2015年06月18日 13:56
  • 476

CreateThread简单那多线程编程

CreateThread简单那多线程编程 作者:vpoet mail:vpoet_sir@163.com 在进行多任务处理的时候我们往往会用到多线程技术,多线程理论上是多个线程同事处...
  • u013018721
  • u013018721
  • 2016年04月10日 13:29
  • 3095

AfxBeginThread创建线程失败

How can AfxBeginThread fail when there are plenty of resources available and the application is a mu...
  • irisjyf
  • irisjyf
  • 2016年04月21日 11:08
  • 560

CreateThread的用法及在Qt等GUI开发中使用CreateThread的一些技巧

Qt中有自己的多线程工具QThread,但是每次都需要继承QThread实现一个自己的类,然后重载其中的run()成员函数,工作量比较大。有的时候只需要执行一个运行时间长的函数来更新GUI及后台的一些...
  • jirryzhang
  • jirryzhang
  • 2017年04月06日 15:14
  • 963

”CreateThread()之后又马上CloseHandle()的问题“ 及 一些注意点

void main() { // Create worker threads for( i=0; i < 2; i++ ) { aThread[i] = CreateThread( ...
  • W_SX12553
  • W_SX12553
  • 2014年09月30日 11:34
  • 903

windows核心编程-创建线程CreateThread

什么是线程 1、在Windows平台上,最终可以利用CPU执行代码的最小尸体就是线程 2、首先从内核角度看,线程是一个内核对象,系统用它来村塾一些关于线程统计信息(比如时间) 3、从编程角度来看,...
  • qq_22423659
  • qq_22423659
  • 2016年11月30日 19:21
  • 195
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:begingthread afxbeginthread createthread
举报原因:
原因补充:

(最多只允许输入30个字)