Windowsコアプログラミング-スレッド作成CreateThread


スレッドとは
1、Windowsプラットフォーム上で、最終的にCPUを利用してコードを実行できる最小死体はスレッドである
2、まずカーネルの角度から见て、スレッドは1つのカーネルのオブジェクトで、システムはそれを使って村塾にいくつかのスレッドの统计情报(例えば时间)について
3、プログラミングの観点から見ると、スレッドはレジスタ状態とスレッドスタックの構造体オブジェクトであり、本質的には関数呼び出しと理解できる(
レジスタ状態は制御CPUで実行し、スタックは局所変数と関数呼び出しパラメータと関数戻りアドレスを格納する)
4、最後に知っておくべきことは、スレッドがいくつかのキューを持つことです(非同期関数呼び出しキューとして簡単に理解できます):
メッセージキュー(GUIスレッドシステム内部で作成されます)
APCキュー(APC関数を呼び出すと作成されます)
(注:これらのキューはスレッド作成時には存在しません)
5、スレッドは実行体
スレッドを使用しない場合
1、一つのアルゴリズムが厳格にスルー化された場合、つまり計算された各ステップが深刻になってから前の操作ステップの結果が得られた場合
2、複数の機能任務があっても比較的に厳格な前後論理関係を持っている場合、マルチスレッドを採用すべきではない
3、もう一つの特殊な状況があります.例えば、1つのサーバーが何千ものクライアントリンクを処理し、異なる要求を処理する必要がある場合、このような
単純なマルチスレッドではなく、スレッドプールを優先的に考慮する必要があります.
デフォルトのスレッド関数には、次のプロトタイプが必要です.
DWORD WINAPI ThreadProc(LPVOID LpParameter);
API:CreateThreadを呼び出すと、新しいプロセスを作成できます.
HANDLE WINAPI CreateThread(
     LPSECURITY_ATTRIBUTES lpThreadAttributes,
     SIZE_T dwStackSize,
     LPTHREAD_START_ROUTINE lpStartAddress,
     LPVOID lpParameter,
     DWORD dwCreationFlags,
     LPDWORD lpThreadId
    );

セキュリティ属性パラメータは、スレッドアクセス文字列(Token)の属性ではなく、新しいプロセスカーネルオブジェクトを作成するセキュリティ属性を指定します.
dwStackSizeは、スレッドの初期時のスタックサイズを指定するために使用されます.通常は0に転送されます.この場合、システムは適切なサイズを使用します.
lpStartAddressは新しいプロセスエントリ関数のアドレスです
lpParameterはスレッドエントリに入力されるパラメータであり,このパラメータは完全に呼び出し者によって使用され,システムは単純にこのパラメータを
スレッド関数に渡され、他の処理は行われません.
dwCreationFlagsはスレッドの作成方法を示し、0であればスレッドが作成されるとすぐに実行されることを示し、CREATE_であればSUSPENDED,
スレッドが作成されると一時停止し、実行されないことを示します.XP以上のシステムでは、このパラメータを1つのSTACK_と組み合わせることもできます.SIZE_PARAM_IS_A_RESERVATION
dwStackSizeの設定は、スレッドスタックに保持された仮想アドレス空間のサイズにすぎず、実際にそれほど多くの物理ページをコミットする必要はありません.
このフラグビットが指定されていない場合、dwStackSizeも実際のコミットメモリのサイズ値です.
lpThreadIdはスレッド固有の識別子を得るために使用される
1、パラメータの結果はランダムで、CPU呼び出しスレッドが完全にランダムであることを示す
2、これはWindowsスレッドのスケジューリングメカニズムの最終的な行為がランダムで、プリエンプトマルチタスクのシステムであることを十分に説明している.
3、そのためマルチスレッドプログラムを分析する場合、あるスレッドが先にスケジューリングされ、あるスレッドが後にスケジューリングされる、すなわち
スレッドの実行順序を仮定できないという動作
4、Windowsスケジューラ時間は時間分割マルチタスク方式でスレッドを順番にスケジューラしているが、このタイムスライスは20 msで、
しかし,マクロの観点から,例えば1秒の時間粒度では,これらのスレッドは「同時」に動作すると考えられる.
5、これらの情報は、スレッドスケジューリングがどのように実行されても、分析時にこれらのスレッドが実際に並列に実行されていると常に考えられていることを示している.
煩雑な分析を簡単にすることができます
6、次の例はスレッド関数を使用するだけで、この関数は共通リソースstdOUTPUTにアクセスし始めた.
7、Windowsシステムでは、ほとんどのカーネルオブジェクトの操作室が厳格に通過化されているため、スレッドがどのように同時実行されても、
最終出力の結果は、呼び出されたWriteConsoleメソッド自体が厳格にシリアル化されているため、完全に秩序化されています(そうでないと出力が混乱します).
8、スレッド自体は同時と考えられる場合があるが、実際には実行する順序を制御したり管理したりする必要がある.
これはマルチスレッド同時制御が必要です
#include
#include
#include
#include

#define GRS_ALLOC(sz) HeapAlloc(GetProcessHeap(),0,sz)
#define GRS_CALLOC(sz) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#define GRS_SAFEFREE(p) if(NULL!=p){HeapFree(GetProcessHeap(),0,p);p=NULL;}

#define GRS_USEPRINTF() TCHAR pBuf[1024]={}
#define GRS_PRINTF(...)\
	StringCchPrintf(pBuf, 1024, __VA_ARGS__); \
	WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pBuf, lstrlen(pBuf), NULL, NULL);

#define MAX_THREADS 10 //     

DWORD WINAPI MyThreadFunction(LPVOID lpParam);
void ErrorHandler(LPTSTR lpszFunction);

//       

typedef struct MyData
{
	int val1;
	int val2;
}MYDATA, *PMYDATA;

int _tmain()
{
	PMYDATA pDataArray[MAX_THREADS];
	DWORD dwThreadIdArray[MAX_THREADS];
	HANDLE hThreadArray[MAX_THREADS];

	//      

	for (int i = 0; i < MAX_THREADS; i++)
	{
		pDataArray[i] = (PMYDATA)GRS_CALLOC(sizeof(MYDATA));
		pDataArray[i]->val1 = i;
		pDataArray[i]->val2 = i + 100;
		hThreadArray[i] = CreateThread(NULL, 0, MyThreadFunction, pDataArray[i], 0, &dwThreadIdArray[i]);
		if (hThreadArray[i] == NULL)
		{
			ErrorHandler(_T("CreateThread"));
			ExitProcess(3);
		}
	}

	WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);

	for (int i = 0; i < MAX_THREADS; i++)
	{
		CloseHandle(hThreadArray[i]);
		GRS_SAFEFREE(pDataArray[i]);
	}
	_tsystem(_T("PAUSE"));
	return 0;
}
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
	//    
	GRS_USEPRINTF();
	PMYDATA pDataArray = (PMYDATA)lpParam;
	GRS_PRINTF(_T("Parameters=%d,%d
"),pDataArray->val1,pDataArray->val2); return 0; } void ErrorHandler(LPTSTR lpszFunction) { GRS_USEPRINTF(); LPVOID lpMsgBuf; DWORD dw = GetLastError();
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		dw,
		MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf,
		0,NULL
		);
	GRS_PRINTF(_T("%s failed with error %d:%s"),lpszFunction,dw,lpMsgBuf);
	LocalFree(lpMsgBuf);
}