一直在用線程,但是一直沒時間認真研究一下
今天從 Jeffrey Richter的<<Programming Applications for Microsoft Windows>>看起,然後慢慢展開
-What's process?
A process actually consists of two components
* A Process Kernel Object
* An Address Space
Process=Process Kernel Object + Address space
hoho,it's really a suprise to me, it's different from my impression on process
-What's Thread?
Similarly, a thread is also consists of two components:
* A Kernel Object that system used to manage thread
* A thread stack~~
-Process vs. Thread
Jeffrey said that the process is inert, it's just a container for threads!!
Threads are created in the context of a process and live their entire life in that process.
By default, there is only one thread in the process --- your entry-point function,(main,wmain,WinMain,wWinMain)
anyway, you can create your own threads, and all these thread live in the process. They
may share the codes,data and kernel object handles
Process require more system resources and memory than threads. Because a process has
a Virtual Address Space, and creating a virtual address space requires a lot of system resources.
Since .exe and .dll files are loaded in to the address space file resources are also required~
Because thread require less overheads than process, you should solve your problem using thread
and avoid create new process. However, this is not a rule, your experience will guide you.
------------------------------------------------------------------------------------------------------------------
-既然每個線程都有一個堆棧那麼,這個堆棧多大呢?
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) 檔案為連結器提供有關被連結程式的匯出、屬性及其他方面的資訊)
可見,預設線程堆棧大小在連結階段可以由程式員指定