更新时间:2023-10-28 19:56
HeapCreate,计算机函数语言,指的是进程中创建辅助堆栈。
你可以在进程中创建辅助堆栈,方法是让线程调用HeapCreate( );函数:
第一个参数flOptions用于修改如何在堆栈上执行各种操作。你可以设定0、HEAP_NO_SERIALIZE、HEAP_GENERATE_EXCEPTIONS、HEAP_CREATE_ENABLE_EXECUTE或者是这些标志的组合。
HEAP_NO_SERIALIZE:对堆的访问是非独占的,如果一个线程没有完成对堆的操作,其它线程也可以进程堆操作,这个开关是非常危险的,应尽量避免使用。
HEAP_GENERATE_EXCEPTIONS:当堆分配内存失败时,会抛出异常。如果不设置,则返回NULL。
HEAP_CREATE_ENALBE_EXECUTE:堆中存放的内容是可以执行的代码。如果不设置,意味着堆中存放的是不可执行的数据。
按照默认设置,堆栈将顺序访问它自己,这样,多个线程就能够分配和释放堆栈中的内存
块而不至于破坏堆栈。
当试图从堆栈分配一个内存块时, HeapAlloc函数(下面将要介绍)必
须执行下列操作:
1、遍历分配的和释放的内存块的链接表。
2、寻找一个空闲内存块的地址。
3、通过将空闲内存块标记为“已分配”分配新内存块。
4、将新内存块添加给内存块链接表。
下面这个例子说明为什么应该避免使用HEAPNOSERIALIZE标志。假定有两个线程试
图同时从同一个堆栈中分配内存块。线程1执行上面的第一步和第二步,获得了空闲内存块的
地址。但是,在该线程可以执行第三步之前,它的运行被线程2抢占,线程2得到一个机会来
执行上面的第一步和第二步。由于线程1尚未执行第三步,因此线程2发现了同一个空闲内存块
的地址。
由于这两个线程都发现了堆栈中它们认为是空闲的内存块,因此线程1更新了链接表,给
新内存块做上了“已分配”的标记。然后线程2也更新了链接表,给同一个内存块做上了“已
分配”标记。两个线程暂时都没有发现问题,但是两个线程得到的是完全相同的内存
块的地址。
这种类型的错误是很难跟踪的,因为它不会立即表现出来。相反,这个错误会在后台等待
着,直到很不适合的时候才显示出来。可能出现的问题是:
· 内存块的链接表已经被破坏。在试图分配或释放内存块之前,这个问题不会被发现。
· 两个线程共享同一个内存块。线程1和线程2会将信息写入同一个内存块。当线程1查看该
内存块的内容时,它将无法识别线程2提供的数据。
· 一个线程可能继续使用该内存块并且将它释放,导致另一个线程改写未分配的内存。这
将破坏该堆栈。
解决这个问题的办法是让单个线程独占对堆栈和它的链接表的访问权,直到该线程执行了
对堆栈的全部必要的操作。如果不使用H E A P _ N O _ S E R I A L I Z E标志,就能够达到这个目的。
只有当你的进程具备下面的一个或多个条件时,才能安全地使用H E A P N O S E R I A L I Z E标志:
· 你的进程只使用一个线程。
· 你的进程使用多个线程,但是它设法使用其他形式的互斥机制,如关键代码段、互斥对
象和信标(第8、9章中介绍),以便设法自己访问堆栈。
如果对是否可以使用H E A P N O S E R I A L I Z E标志没有把握,那么请不要使用它。如果不
使用该标志,每当调用堆栈函数时,线程的运行速度会受到一定的影响,但是不会破坏你的堆
栈及其数据。
另一个标志H E A P G E N E R AT E E X C E P T I O N S,会在分配或重新分配堆栈中的内存块的尝
试失败时,导致系统引发一个异常条件。所谓异常条件,只不过是系统使用的另一种方法,以
便将已经出现错误的情况通知你的应用程序。有时在设计应用程序时让它查看异常条件比查看
返回值要更加容易些。异常条件将在第2 3、2 4和2 5章中介绍。
H e a p C r e a t e的第二个参数d w I n i t i a l S i z e用于指明最初提交给堆栈的字节数。如果必要的话,
H e a p C r e a t e函数会将这个值将向上取整为C P U页面大小的倍数。最后一个参数d w M a x i m u m S i z e用于指明堆栈能够扩展到的最大值(即系统能够为堆栈保留的地址空间的最大数量)。如果
d w M a x i m u m S i z e大于0,那么你创建的堆栈将具有最大值。如果尝试分配的内存块会导致堆栈
超过其最大值,那么这种尝试就会失败。
如果d w M a x i m u m S i z e的值是0,那么可以创建一个能够扩展的堆栈,它没有内在的限制。
从堆栈中分配内存块只需要使堆栈不断扩展,直到物理存储器用完为止。如果堆栈创建成功,
H e a p C r e a t e函数返回一个句柄以标识新堆栈。该句柄可以被其他堆栈函数使用。
若要从堆栈中分配内存块,只需要调用H e a p A l l o c函数