Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A função CreateThread cria um novo thread para um processo. O thread de criação deve especificar o endereço inicial do código que o novo thread deve executar. Normalmente, o endereço inicial é o nome de uma função definida no código do programa (para obter mais informações, consulte ThreadProc). Essa função usa um único parâmetro e retorna um valor DWORD . Um processo pode ter vários threads executando simultaneamente a mesma função.
Veja a seguir um exemplo simples que demonstra como criar um thread que executa a função MyThreadFunctiondefinida localmente.
O thread de chamada usa a função WaitForMultipleObjects para persistir até que todos os threads de trabalho tenham sido encerrados. A thread chamadora fica bloqueada enquanto aguarda; para continuar o processamento, uma thread chamadora usaria WaitForSingleObject e aguardaria que cada thread de trabalho sinalize seu objeto de espera. Observe que, se você fechar o identificador de um thread de trabalho antes de ele ser encerrado, isso não encerrará o thread de trabalho. No entanto, o identificador não estará disponível para ser usado em chamadas de função posteriores.
#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);
}
A função MyThreadFunction evita o uso da biblioteca de tempo de execução da linguagem C (CRT), pois muitas de suas funções não são seguras para threads, principalmente se você não estiver usando a CRT multithread. Se você quiser usar o CRT em uma função ThreadProc, use a função _beginthreadex em vez dela.
Note
Alternativas modernas do C++: Para um novo código, considere usar std::thread (C++11) ou std::jthread (C++20, com ingressamento automático e cancelamento cooperativo via std::stop_token). Elas fornecem gerenciamento de threads baseado em RAII e seguro em termos de tipo. Use CreateThread quando precisar de funcionalidades específicas do Win32, como atributos de segurança, controle do tamanho da pilha ou criação de thread em estado suspenso. Para trabalho assíncrono que não requer uma thread dedicada, prefira std::async, a API de pool de threads do Windows, ou as coroutines do C++/WinRT (co_await).
É arriscado passar o endereço de uma variável local se a thread que a criou for encerrada antes da nova thread, pois o ponteiro fica inválido. Em vez disso, passe um ponteiro para a memória alocada dinamicamente ou faça com que o thread de criação aguarde a conclusão do novo thread. Os dados também podem ser passados do thread de criação para o novo thread usando variáveis globais. Com variáveis globais, geralmente é necessário sincronizar o acesso por vários threads. Para obter mais informações sobre sincronização, consulte Sincronizando a execução de vários threads.
O thread de criação pode usar os argumentos para CreateThread para especificar o seguinte:
- Os atributos de segurança do identificador do novo thread. Esses atributos de segurança incluem um indicador de herança que determina se o identificador pode ser herdado por processos filhos. Os atributos de segurança também incluem um descritor de segurança, que o sistema usa para executar verificações de acesso em todos os usos subsequentes do identificador do thread antes que o acesso seja concedido.
- O tamanho da pilha inicial do novo thread. A pilha do thread é alocada automaticamente no espaço de memória do processo; o sistema aumenta a pilha conforme necessário e a libera quando o thread termina. Para obter mais informações, consulte o Tamanho da Pilha de Threads.
- Um sinalizador de criação que permite criar o thread em um estado suspenso. Quando suspenso, o thread não é executado até que a função ResumeThread seja chamada.
Você também pode criar um thread chamando a função CreateRemoteThread . Essa função é usada por processos de depurador para criar um thread executado no espaço de endereço do processo que está sendo depurado.
Tópicos relacionados: