手动测试和修改多线程中栈空间大小。

2024-03-01 13:48

本文主要是介绍手动测试和修改多线程中栈空间大小。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

每个线程都有一个堆栈那么,这个堆栈多大呢?

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

在创建线程的时候可以指定堆栈大 小,dwStackSize=0则使用默认大小


-那默认大小又是多少?

      写个小程序算一下~

#include <stdio.h>
#include <windows.h>

#define STACK_SIZE 0.5*1024*1024

DWORD WINAPI ThreadFunc(PVOID pvParam)
{
      DWORD dwRet = 0;
      printf("%-3d:0x%x\n",pvParam,&dwRet); 
      return dwRet;
}

int
main(int,char**)
{
      DWORD dwTid;
      printf("Main:0x%x\n",&dwTid); 
      for(int i=0;i<50;i++)
        CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,0,&dwTid); // 莫小注:原作者这处代码有错,这不能修改线程栈大小

      Sleep(2000);
    return 0; 
}

输出:

Main:0x12ff78
0       :0x50ffb0
1       :0x60ffb0
2       :0x70ffb0
3       :0x80ffb0
4       :0x90ffb0

0x60ffb0 - 0x50ffb0 = 0x100000 byte = 1MB

那么这个小程序中线程最小堆栈大小为1MB. (对么?为什么呢?后面有验证)
将STACK_SIZE换成0, 结果和上面一样
将STACK_SIZE换成2, 结果变成2MB

以下是从MSDN中查到的

Generally, the reserve size is the default reserve size specified in the executable header. However, if the initially committed size specified by dwStackSize is larger than the default reserve size, the reserve size is this new commit size rounded up to the nearest multiple of 1 MB.

根据winnt.h中的      IMAGE_OPTIONAL_HEADER结构体
typedef struct _IMAGE_OPTIONAL_HEADER {
       //
        // Standard fields.
        //

        WORD        Magic;
        BYTE        MajorLinkerVersion;
        BYTE        MinorLinkerVersion;
        DWORD       SizeOfCode;
        DWORD       SizeOfInitializedData;
        DWORD       SizeOfUninitializedData;
        DWORD       AddressOfEntryPoint;
        DWORD       BaseOfCode;
        DWORD       BaseOfData;

        //
        // NT additional fields.
        //

        DWORD       ImageBase;
        DWORD       SectionAlignment;
        DWORD       FileAlignment;
        WORD        MajorOperatingSystemVersion;
        WORD        MinorOperatingSystemVersion;
        WORD        MajorImageVersion;
        WORD        MinorImageVersion;
        WORD        MajorSubsystemVersion;
        WORD        MinorSubsystemVersion;
        DWORD       Win32VersionValue;
        DWORD       SizeOfImage;
        DWORD       SizeOfHeaders;
        DWORD       CheckSum;
        WORD        Subsystem;
        WORD        DllCharacteristics;
        DWORD       SizeOfStackReserve;
        DWORD       SizeOfStackCommit;
        DWORD       SizeOfHeapReserve;
        DWORD       SizeOfHeapCommit;
        DWORD       LoaderFlags;
        DWORD       NumberOfRvaAndSizes;
        IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

我推测,应该可以在链接期间指定栈大小
查看link.exe的参数

/STACK:reserve[,commit]
果然如此~~

看到网上有人问如何改变默认的线程堆栈大小,在MSDN中有答案:

The default size for the reserved and initially committed stack memory is specified in the executable file header. Thread or fiber creation fails if there is not enough memory to reserve or commit the number of bytes requested. To specify a different default stack size for all threads and fibers, use the STACKSIZE statement in the module definition (.def) file. For more information on these default sizes and how to change them, see the documentation included with your linker.

(模块定义 (.def) 文件为链接器提供有关被链接程序的导出、属性及其他方面的信息)

可见,默认线程堆栈大小在链接阶段可以由程序员指定

 

 

以上部分载自他人空间.

MSDN中有段话很重要:

To change the reserved stack size, set the dwCreationFlags parameter of CreateThread or CreateRemoteThread toSTACK_SIZE_PARAM_IS_A_RESERVATION and use the dwStackSize parameter. 

我用MSDN2001版查看的时候,它有注明STACK_SIZE_PARAM_IS_A_RESERVATION 适用于XP系统, 在MSDN2008版没注明了,我是在XP下测试的

下面是我改的测试代码:

代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 #include "stdafx.h"
#include <stdio.h>
#include <windows.h>#define STACK_SIZE 64*1024 // 设置线程栈为64KDWORD WINAPI ThreadFunc(PVOID pvParam)
{DWORD dwRet = 0;printf("%-3d:0x%x\n",pvParam,&dwRet);Sleep(2000);  // 避免线程退出,这个线程栈地址又被分配给其它新创建的线程return dwRet;
}int main(int,char**)
{DWORD dwTid;printf("Main:0x%x\n",&dwTid);HANDLE handles[10];for(int i=0;i<10;i++){handles[i] = CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,STACK_SIZE_PARAM_IS_A_RESERVATION ,&dwTid);Sleep(100); // 保证每次Create后得到的线程栈地址是递增的}for(int i=0; i<10; i++){CloseHandle(handles[i]);}getchar();return 0;
}

-----CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,STACK_SIZE_PARAM_IS_A_RESERVATION ,&dwTid);

运行结果:


每次相差(10000)x = (655366)d = 64*1024, 设置成功,64K.

另外, Linux平台的栈默认大小应该是8192KB, Windows平台的栈默认大小应该是1024KB, 项目移植的时候要注意设置, 免得空间不足, 分配失败




这篇关于手动测试和修改多线程中栈空间大小。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/762649

相关文章

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

MySQL之InnoDB存储页的独立表空间解读

《MySQL之InnoDB存储页的独立表空间解读》:本文主要介绍MySQL之InnoDB存储页的独立表空间,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、独立表空间【1】表空间大小【2】区【3】组【4】段【5】区的类型【6】XDES Entry区结构【

使用Python进行GRPC和Dubbo协议的高级测试

《使用Python进行GRPC和Dubbo协议的高级测试》GRPC(GoogleRemoteProcedureCall)是一种高性能、开源的远程过程调用(RPC)框架,Dubbo是一种高性能的分布式服... 目录01 GRPC测试安装gRPC编写.proto文件实现服务02 Dubbo测试1. 安装Dubb

如何在Mac上彻底删除Edge账户? 手动卸载Edge浏览器并清理残留文件技巧

《如何在Mac上彻底删除Edge账户?手动卸载Edge浏览器并清理残留文件技巧》Mac上的Edge账户里存了不少网站密码和个人信息,结果同事一不小心打开了,简直尴尬到爆炸,想要卸载edge浏览器并清... 如果你遇到 Microsoft Edge 浏览器运行迟缓、频繁崩溃或网页加载异常等问题,可以尝试多种方

Python的端到端测试框架SeleniumBase使用解读

《Python的端到端测试框架SeleniumBase使用解读》:本文主要介绍Python的端到端测试框架SeleniumBase使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录SeleniumBase详细介绍及用法指南什么是 SeleniumBase?SeleniumBase

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

SQL Server修改数据库名及物理数据文件名操作步骤

《SQLServer修改数据库名及物理数据文件名操作步骤》在SQLServer中重命名数据库是一个常见的操作,但需要确保用户具有足够的权限来执行此操作,:本文主要介绍SQLServer修改数据... 目录一、背景介绍二、操作步骤2.1 设置为单用户模式(断开连接)2.2 修改数据库名称2.3 查找逻辑文件名

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

MySQL启动报错:InnoDB表空间丢失问题及解决方法

《MySQL启动报错:InnoDB表空间丢失问题及解决方法》在启动MySQL时,遇到了InnoDB:Tablespace5975wasnotfound,该错误表明MySQL在启动过程中无法找到指定的s... 目录mysql 启动报错:InnoDB 表空间丢失问题及解决方法错误分析解决方案1. 启用 inno