Creating Threads Using the win32 API

The CreateThread() API call can be used to create and run a thread. A thread needs to have code to execute, and we will provide this via a ThreadProc callback function. A ThreadProc function takes a single argument of type LPVOID and returns a DWORD value.

The CreateThread() function returns a thread handle that is valid only within our process. The handle refers to the kernel thread object managing the new thread. Most of the thread API class use this thread handle.

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

DWORD WINAPI threadFunc(LPVOID lPtr);

int _tmain(int argc, _TCHAR* argv[])
{

	HANDLE hThread;


	printf("In main.\n");

	hThread = CreateThread(
		NULL, //default security
		0, //default stack size
		threadFunc, //LPTHREAD_START_ROUTINE
		0, //argument to threadFunc
		0, //creation flags
		0
		);

	if(hThread!=NULL){
		printf("Thread created successfully.\n");
	} else {
		printf("Error creating thread.\n");
	}

	//give called thread time to finish
	Sleep(1500);

	return 0;
}

DWORD WINAPI threadFunc(LPVOID lPtr){
	printf("In the thread.\n");

	return 0;
}

Note that the CreateThread() function returns immediately, so that the calling routine and the new thread execute simultaneously. If the primary thread dies before the thread functions have finished executing, then all threads will be forcibly terminated, and will not have a chance to finish.

The CreateThread() function takes a number of parameters, most of which we should provide with a NULL or 0. The first parameter is a pointer to a SECURITY_ATTRIBUTES structure, which is used to govern who can access the new thread. We can set this parameter to NULL. The second parameter indicates the amount of stack space to be allocated for the new thread. Here we should specify 0, as this causes the stack size to default to the default size of the executable.

The third and fourth parameters are most important, as these specify the address of the ThreadProc function, and a pointer to any arguments we want to supply to it. These arguments are passed via a single void* pointer, so we must ensure that the data is cast back into the right types in the new thread.

The fifth parameter lets us supply flag values which determine how the thread behaves when it is created. Here we will pass 0.

#include <Windows.h>
#include <stdlib.h> 
#include <stdio.h>

DWORD WINAPI TPFunction(LPVOID lPtr);

int _tmain(int argc, _TCHAR* argv[])
{
	int num = 73;
	void *vPtr = &num;

	HANDLE hThreadHandle = CreateThread(
		NULL, //default security
		0, //default stack size
		TPFunction, //function
		vPtr, //argument
		0,
		0
		);

	for(int i = 0; i < 10; i++){
		printf("In main %d \t", i+1);
		Sleep(100);
	}

	return 0;
}

DWORD WINAPI TPFunction(LPVOID lPtr){
        //cast the void pointer to an int pointer
       //then dereference it
	printf("...Received %d in the thread.\n", *((int*)lPtr));

	return 0;
}

The final parameter is a pointer to a DWORD value that can be used to store the thread ID. The thread ID is a unique global value that any or thread or process can use to refer to our thread.

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

DWORD WINAPI theFunction(LPVOID lPtr);

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD dwIDOne, dwIDTwo;
	HANDLE hThreadOne, hThreadTwo;
	int iValOne = 100;
	int iValTwo = iValOne * 2;

	hThreadOne = CreateThread(
		NULL,
		0,
		theFunction,
		(void*)&iValOne,
		0,
		&dwIDOne
		);
	
	if(hThreadOne!=NULL){
		printf("Thread %d created.\n", dwIDOne);
	}

	hThreadTwo = CreateThread(
		NULL,
		0,
		theFunction,
		(void*)&iValTwo,
		0,
		&dwIDTwo
		);

	if(hThreadTwo!=NULL){
		printf("Thread %d created.\n", dwIDTwo);
	}

	for(int i = 0; i < 10; i++){
		printf("In main...\n");
		Sleep(10 * i);
	}

	

	return 0;
}

DWORD WINAPI theFunction(LPVOID lPtr){
	printf("In the new thread, ID %d.\n", GetCurrentThreadId());
	Sleep(100 + *((int*)lPtr));
	printf("Finishing thread %d.\n", GetCurrentThreadId());

	return 0;
}

Note the use of the GetCurrentThreadId() function to get the current ID for the thread.

The GetExitCodeThread() function gets the exit code from the ThreadProc function associated with the handle. The GetExitCodeThread() function has two paramters, the HANDLE of the thread we want the exit code of, and a pointer to a DWORD value to store the exit code.

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

DWORD WINAPI theFunc(LPVOID lPtr);

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD dwExitCode;
	DWORD dwThreadID;

	HANDLE hT = CreateThread(
		NULL,
		0,
		theFunc,
		0,
		0,
		&dwThreadID
		);
	
	//wait for the thread to exit
	while(TRUE){
		GetExitCodeThread(hT, &dwExitCode);
		if(dwExitCode == STILL_ACTIVE){
			printf("Thread %d is still running.\n", dwThreadID);
			Sleep(20);
			continue;
		}
		printf("Thread exit code was %d.\n", dwExitCode);
		break;
	}

	return 0;
}

DWORD WINAPI theFunc(LPVOID lPtr){
	for(int i = 0; i < 10; i++){
		Sleep(20 * i);
	}

	return 0;
}

Note that the GetExitCodeThread() function itself returns a Boolean value.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s