Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die CreateThread-Funktion erstellt einen neuen Thread für einen Prozess. Der Erstellungsthread muss die Startadresse des Codes angeben, den der neue Thread ausführen soll. In der Regel ist die Startadresse der Name einer im Programmcode definierten Funktion (weitere Informationen finden Sie unter ThreadProc). Diese Funktion verwendet einen einzelnen Parameter und gibt einen DWORD-Wert zurück. Ein Prozess kann mehrere Threads gleichzeitig ausführen, um dieselbe Funktion auszuführen.
Es folgt ein einfaches Beispiel, das veranschaulicht, wie ein neuer Thread erstellt wird, der die lokal definierte Funktion MyThreadFunctionausführt.
Der aufrufende Thread verwendet die WaitForMultipleObjects-Funktion , um beizubehalten, bis alle Arbeitsthreads beendet wurden. Der aufrufende Thread blockiert, während er wartet; um die Verarbeitung fortzusetzen, würde ein aufrufender Thread WaitForSingleObject verwenden und warten, bis jeder Workerthread das Warteobjekt signalisiert. Beachten Sie, dass ein Workerthread nicht beendet wird, wenn Sie das Handle eines Workerthreads schließen, bevor dieser beendet ist. Das Handle ist jedoch für die Verwendung in nachfolgenden Funktionsaufrufen nicht verfügbar.
#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;
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;
// 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\n"),
pDataArray->val1, pDataArray->val2);
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
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);
}
Die MyThreadFunction Funktion vermeidet die Verwendung der C-Laufzeitbibliothek (C Run-Time Library, CRT), da viele seiner Funktionen nicht threadsicher sind, insbesondere wenn Sie das Multithread-CRT nicht verwenden. Wenn Sie den CRT in einer ThreadProc Funktion verwenden möchten, verwenden Sie stattdessen die _beginthreadex-Funktion .
Note
Moderne C++-Alternativen: Ziehen Sie für neuen Code die Verwendung von std::thread (C++11) oder std::jthread (C++20, mit automatischem Joinen und kooperativem Abbruch über std::stop_token) in Betracht. Diese bieten typsichere, RAII-basierte Threadverwaltung. Verwenden Sie CreateThread , wenn Sie Win32-spezifische Features wie Sicherheitsattribute, Stack Size Control oder angehaltene Threaderstellung benötigen. Verwenden Sie für asynchrone Vorgänge, die keinen dedizierten Thread erfordern, bevorzugt std::async, die Windows-Threadpool-API oder C++/WinRT-Koroutinen (co_await).
Es ist riskant, die Adresse einer lokalen Variablen zu übergeben, wenn der Erstellungsthread vor dem neuen Thread beendet wird, da der Zeiger ungültig wird. Übergeben Sie stattdessen entweder einen Zeiger auf dynamisch zugewiesenen Speicher, oder lassen Sie den erzeugenden Thread warten, bis der neue Thread terminiert. Daten können auch vom Erstellungsthread mithilfe globaler Variablen an den neuen Thread übergeben werden. Bei globalen Variablen ist es in der Regel erforderlich, den Zugriff durch mehrere Threads zu synchronisieren. Weitere Informationen zur Synchronisierung finden Sie unter Synchronisieren der Ausführung mehrerer Threads.
Der erstellende Thread kann die Argumente zum ErstellenThread verwenden, um Folgendes anzugeben:
- Die Sicherheitsattribute für das Handle für den neuen Thread. Diese Sicherheitsattribute enthalten ein Vererbungskennzeichnung, das bestimmt, ob das Handle von untergeordneten Prozessen geerbt werden kann. Die Sicherheitsattribute enthalten auch einen Sicherheitsdeskriptor, den das System verwendet, um Zugriffsprüfungen für alle nachfolgenden Verwendungen des Threadhandle durchzuführen, bevor der Zugriff gewährt wird.
- Die anfängliche Stackgröße des neuen Threads. Der Stapel des Threads wird automatisch im Arbeitsspeicher des Prozesses zugewiesen; das System erhöht den Stapel nach Bedarf und gibt ihn frei, wenn der Thread beendet wird. Weitere Informationen finden Sie unter Threadstapelgröße.
- Ein Erstellungsflag, mit dem Sie den Thread in einem suspendierten Zustand erstellen können. Wenn der Thread angehalten ist, läuft er erst dann weiter, wenn die ResumeThread-Funktion aufgerufen wird.
Sie können auch einen Thread erstellen, indem Sie die CreateRemoteThread-Funktion aufrufen. Diese Funktion wird von Debuggerprozessen verwendet, um einen Thread zu erstellen, der im Adressraum des zu debuggenden Prozesses ausgeführt wird.
Zugehörige Themen