一个进程(process)最多可以开辟多少个线程(thread)

进程与线程的关系

简单复习一下:一个”进程“代表中计算机中实际跑起来的一个程序,在现代操作系统的保护模式下,每个进程拥有自己独立的进程地址空间和上下文堆栈。但是就一个程序本身执行的操作来说,进程其实什么也不做(不执行任何进程代码),它只是提供一个大环境容器,在进程中实际的执行体是”线程“。因此一个进程至少得有一个线程,我们把这个线程称之为”主线程“,也就是说,一个进程至少要有一个主线程。

 

进程中创建线程的限制

默认情况下,一个线程的栈要预留1M的内存空间,而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程。但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小。

#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <assert.h>

#define DEFAULT_STACK//注释该行,则开辟的线程默认栈大小为512KB

volatile bool g_bExitThread = false;
HANDLE g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);


UINT WINAPI WorkThread(void* ptr)
{
	int nThreadID = *((int*)ptr);	
	printf("%d线程启动\n", nThreadID);

	SetEvent(g_hEvent);
	while(!g_bExitThread)
	{
		Sleep(1);//权宜之计,让线程不要提前退出
	}

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	for(int i=0; i<5000; i++)
	{

#ifdef DEFAULT_STACK
		HANDLE _handle = (HANDLE)_beginthreadex(NULL, 0, WorkThread, &i, 0, NULL);
#else
		HANDLE _handle = (HANDLE)_beginthreadex(NULL, 512*1024, WorkThread, &i, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
#endif		
		
		if (_handle == 0)
		{
			if(GetLastError() == 8)
			{
				printf("开启线程失败,存储空间不足!\n");
			}
			else
			{
				printf("开启线程失败,错误号%d\n", GetLastError());
			}
			break;
		}
		WaitForSingleObject(g_hEvent, INFINITE);
	}
	getchar();
	return 0;
}

使用默认的线程栈大小(1M),从输出结果来看,一个进程最大能开辟的线程数为:1451

将上面代码的“#define DEFAULT_STACK”注释掉,使用线程的栈大小改为512KB。从输出结果来看,一个进程最大能开辟的线程数为:2284

 

如何突破2000个限制

可以通过连接时修改默认栈大小,将其改的比较小,这样就可以多开一些线程。 如将默认栈的大小改成512K,这样理论上最多就可以开4096个线程。但即使物理内存再大,一个进程中可以起的线程总要受到2GB这个内存空间的限制。比方说你的机器装了64GB物理内存,但每个进程的内存空间还是4GB,其中用户态可用的还是2GB。

如果是同一台机器内的话,能起多少线程也是受内存限制的。每个线程对象都要占用非页面内存,而非页面内存也是有限的,当非页面内存被耗尽时,也就无法创建线程了。如果物理内存非常大,同一台机器内可以跑的线程数目的限制值会越来越大。
 

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页