#define _WIN32_WINNT 0x0500

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

#define MAX_THREAD 7
#define MAX_THREAD_NUMBER (MAX_THREAD*5)

HANDLE handles[MAX_THREAD_NUMBER];

CRITICAL_SECTION cs;


//THREAD_PRIORITY_ABOVE_NORMAL Indicates 1 point above normal priority for the priority class. 
//THREAD_PRIORITY_BELOW_NORMAL Indicates 1 point below normal priority for the priority class. 
//THREAD_PRIORITY_HIGHEST Indicates 2 points above normal priority for the priority class. 
//THREAD_PRIORITY_IDLE Indicates a base-priority level of 1 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 16 for REALTIME_PRIORITY_CLASS processes. 
//THREAD_PRIORITY_LOWEST Indicates 2 points below normal priority for the priority class. 
//THREAD_PRIORITY_NORMAL Indicates normal priority for the priority class. 
//THREAD_PRIORITY_TIME_CRITICAL Indicates a base-priority level of 15 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 31 for REALTIME_PRIORITY_CLASS processes. 

int priority[MAX_THREAD] = 
{
	THREAD_PRIORITY_IDLE,
	THREAD_PRIORITY_LOWEST,
	THREAD_PRIORITY_BELOW_NORMAL,
	THREAD_PRIORITY_NORMAL,
	THREAD_PRIORITY_ABOVE_NORMAL,	
	THREAD_PRIORITY_HIGHEST,	
	THREAD_PRIORITY_TIME_CRITICAL
};

char* priorityName[MAX_THREAD] =
{
	"THREAD_PRIORITY_IDLE",
	"THREAD_PRIORITY_LOWEST",
	"THREAD_PRIORITY_BELOW_NORMAL",
	"THREAD_PRIORITY_NORMAL",
	"THREAD_PRIORITY_ABOVE_NORMAL", 	
	"THREAD_PRIORITY_HIGHEST",	
	"THREAD_PRIORITY_TIME_CRITICAL",
};

char buffer[65535]={0};
int counter = 0;
DWORD myClass = 0;

#if 0
DWORD WINAPI threadRun(void* param)
{
	int index = (int)(param);
	int level = 0;

	if (SetPriorityClass(handles[index], REALTIME_PRIORITY_CLASS))
	{
		if (SetThreadPriority(handles[index], priority[index]))
		{
			while (true)
			{	
				level = GetThreadPriority(handles[index]);
				EnterCriticalSection(&cs);
				
				for (int i =0 ; i < MAX_THREAD; i ++)
				{
					if (level == priority[i])
					{
						printf("thread[%d] priority=%s\n", index, priorityName[i]);
						break;
					}
				}
				LeaveCriticalSection(&cs);
			}
		}		
	}

	return index;
}
#else
#define BUFFER_SIZE 10240
char contents[BUFFER_SIZE]={0};
DWORD WINAPI threadRun(void* param)
{
	int index = (int)(param);
	int theClass = index%MAX_THREAD;
	int level = 0;
	bool bStop = false;
	DWORD dwCPU = 0;
	HANDLE fileHandle = INVALID_HANDLE_VALUE;
	char fileName[64];
	
	DWORD dwWritten;
	
	// you cannot set REALTIME_PRIORITY_CLASS or anything higher than normal
	if (SetThreadPriorityBoost(handles[index], TRUE))
	{		
		if (SetThreadPriority(handles[index], priority[theClass]))
		{
			if (theClass % MAX_THREAD < 6)
			{
				dwCPU = 0;
			}
			else
			{
				sprintf(fileName, "output%d.txt", index);
				fileHandle = CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
				if (fileHandle == INVALID_HANDLE_VALUE)
				{
					bStop = true;
				}				
				dwCPU = 1;
			}

			if (SetThreadIdealProcessor(handles[index], dwCPU) == -1)
			{
				bStop = true;
			}
		

			while (!bStop)
			{	
				if (theClass >= 6)
				{
					WriteFile(fileHandle, contents, BUFFER_SIZE, &dwWritten, NULL);
				}
				else
				{
					for (int i = 0; i < 1000; i ++)
					{
						double val = log(10240);
						val = exp(10240);
						val = log10(val);
					}
				}
				//EnterCriticalSection(&cs);
				buffer[counter++] = index;
				if (counter >= 65535)
				{
					bStop = true;
				}
				//LeaveCriticalSection(&cs);
			}
			if (theClass < 6 && fileHandle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(fileHandle);
			}
		}	
	}
	else
	{
		printf("what?????????????????????\n");
	}
	return index;
}
#endif


int main()
{
	int i;
	HANDLE handle = NULL;
	int number[MAX_THREAD_NUMBER]= {0};
	InitializeCriticalSection(&cs);

	memset(contents, '9', BUFFER_SIZE);
	for (i = 0; i < MAX_THREAD_NUMBER; i ++)
	{
		handles[i] = CreateThread(NULL, 0, threadRun, (void*)i, 0, NULL);
	}
	for (i = 0; i < MAX_THREAD_NUMBER; i ++)
	{
		WaitForSingleObject(handles[i], INFINITE);
	}
	if (counter >=65535)
	{
		counter = 65535;
	}
	for (i = 0; i < counter; i ++)
	{
		number[buffer[i]] ++;
		printf("thread[%d] with priority %s\n", buffer[i], priorityName[buffer[i]%MAX_THREAD]);
	}

	printf("********************************\n\n");
	for (i = 0; i < MAX_THREAD_NUMBER ; i ++)
	{
		printf("thread[%d] with priority %s runs %d\n", i, priorityName[i%MAX_THREAD], number[i]);
	}

	handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
	myClass = GetPriorityClass(handle);
	switch (myClass)
	{
	case ABOVE_NORMAL_PRIORITY_CLASS:
		printf("ABOVE_NORMAL_PRIORITY_CLASS");
		break;
	case BELOW_NORMAL_PRIORITY_CLASS:
		printf("BELOW_NORMAL_PRIORITY_CLASS");
		break;
	case HIGH_PRIORITY_CLASS:
		printf("HIGH_PRIORITY_CLASS");
		break;
	case IDLE_PRIORITY_CLASS:
		printf("IDLE_PRIORITY_CLASS");
		break;
	case NORMAL_PRIORITY_CLASS:
		printf("NORMAL_PRIORITY_CLASS");
		break;
	case REALTIME_PRIORITY_CLASS:
		printf("REALTIME_PRIORITY_CLASS");
		break;
	}

	return 0;
}
