154 lines
4.5 KiB
C++
154 lines
4.5 KiB
C++
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <strsafe.h>
|
|
|
|
#define MAX_THREADS 3
|
|
#define BUF_SIZE 255
|
|
|
|
DWORD WINAPI MyThreadFunction(LPVOID lpParam);
|
|
void ErrorHandler(LPCTSTR lpszFunction);
|
|
|
|
// Sample custom data structure for threads to use.
|
|
// This is passed by void pointer so it can be any data type
|
|
// that can be passed using a single void pointer (LPVOID).
|
|
typedef struct MyData {
|
|
int val1;
|
|
int val2;
|
|
} MYDATA, *PMYDATA;
|
|
|
|
bool running = true;
|
|
|
|
int _tmain() {
|
|
PMYDATA pDataArray[MAX_THREADS];
|
|
DWORD dwThreadIdArray[MAX_THREADS];
|
|
HANDLE hThreadArray[MAX_THREADS];
|
|
|
|
// Create MAX_THREADS worker threads.
|
|
|
|
for ( int i = 0; i < MAX_THREADS; i++ ) {
|
|
// Allocate memory for thread data.
|
|
|
|
pDataArray[i] = (PMYDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof(MYDATA));
|
|
|
|
if ( pDataArray[i] == NULL ) {
|
|
// If the array allocation fails, the system is out of memory
|
|
// so there is no point in trying to print an error message.
|
|
// Just terminate execution.
|
|
ExitProcess(2);
|
|
}
|
|
|
|
// Generate unique data for each thread to work with.
|
|
|
|
pDataArray[i]->val1 = i;
|
|
pDataArray[i]->val2 = i + 100;
|
|
|
|
// Create the thread to begin execution on its own.
|
|
|
|
hThreadArray[i] = CreateThread(
|
|
NULL, // default security attributes
|
|
0, // use default stack size
|
|
MyThreadFunction, // thread function name
|
|
pDataArray[i], // argument to thread function
|
|
0, // use default creation flags
|
|
&dwThreadIdArray[i]); // returns the thread identifier
|
|
|
|
|
|
// Check the return value for success.
|
|
// If CreateThread fails, terminate execution.
|
|
// This will automatically clean up threads and memory.
|
|
|
|
if ( hThreadArray[i] == NULL ) {
|
|
ErrorHandler(TEXT("CreateThread"));
|
|
ExitProcess(3);
|
|
}
|
|
} // End of main thread creation loop.
|
|
|
|
// Wait until all threads have terminated.
|
|
|
|
WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
|
|
|
|
// Close all thread handles and free memory allocations.
|
|
|
|
for ( int i = 0; i < MAX_THREADS; i++ ) {
|
|
CloseHandle(hThreadArray[i]);
|
|
if ( pDataArray[i] != NULL ) {
|
|
HeapFree(GetProcessHeap(), 0, pDataArray[i]);
|
|
pDataArray[i] = NULL; // Ensure address is not reused.
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
|
|
HANDLE hStdout;
|
|
PMYDATA pDataArray;
|
|
|
|
TCHAR msgBuf[BUF_SIZE];
|
|
size_t cchStringSize;
|
|
DWORD dwChars;
|
|
|
|
// Make sure there is a console to receive output results.
|
|
|
|
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if ( hStdout == INVALID_HANDLE_VALUE )
|
|
return 1;
|
|
|
|
int counter = 0;
|
|
while (running) {
|
|
// Cast the parameter to the correct data type.
|
|
// The pointer is known to be valid because
|
|
// it was checked for NULL before the thread was created.
|
|
|
|
pDataArray = (PMYDATA)lpParam;
|
|
|
|
// Print the parameter values using thread-safe functions.
|
|
|
|
StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d, [%d]\n"),
|
|
pDataArray->val1, pDataArray->val2, counter++);
|
|
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
|
|
WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
|
|
Sleep(1000 + 1000 * pDataArray->val1 );
|
|
if ( counter > 5 )
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void ErrorHandler(LPCTSTR lpszFunction) {
|
|
// Retrieve the system error message for the last-error code.
|
|
|
|
LPVOID lpMsgBuf;
|
|
LPVOID lpDisplayBuf;
|
|
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);
|
|
|
|
// Display the error message.
|
|
|
|
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
|
|
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
|
|
StringCchPrintf((LPTSTR)lpDisplayBuf,
|
|
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
|
|
TEXT("%s failed with error %d: %s"),
|
|
lpszFunction, dw, lpMsgBuf);
|
|
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
|
|
|
|
// Free error-handling buffer allocations.
|
|
|
|
LocalFree(lpMsgBuf);
|
|
LocalFree(lpDisplayBuf);
|
|
}
|