Multithreading: Criando threads de trabalho no MFC
Um thread de trabalho é comumente usado para lidar com tarefas em segundo plano que o usuário não deve ter que esperar para continuar usando seu aplicativo. Tarefas como recálculo e impressão em segundo plano são bons exemplos de threads de trabalho. Este tópico detalha as etapas necessárias para criar um thread de trabalho. Os tópicos incluem:
Criar um thread de trabalho é uma tarefa relativamente simples. Somente duas etapas são necessárias para executar o thread: implementar a função de controle e iniciar o thread. Não é necessário derivar uma classe do CWinThread. Você poderá derivar uma classe se precisar de uma versão especial de CWinThread
, mas ela não é necessária para a maioria dos threads de trabalho simples. Você pode usar CWinThread
sem modificação.
Iniciando o thread
Há duas versões sobrecarregadas de AfxBeginThread
: uma que só pode criar threads de trabalho e outra que pode criar threads de interface do usuário e threads de trabalho. Para iniciar a execução do thread de trabalho usando a primeira sobrecarga, chame AfxBeginThread, fornecendo as seguintes informações:
O endereço da função de controle.
O parâmetro a ser passado para a função de controle.
(Opcional) A prioridade desejada do thread. O padrão é a prioridade normal. Para obter mais informações sobre os níveis de prioridade disponíveis, consulte SetThreadPriority no SDK do Windows.
(Opcional) O tamanho de pilha desejado para o thread. O padrão é a mesma pilha de tamanho que o thread de criação.
(Opcional) CREATE_SUSPENDED se você quiser que o thread seja criado em um estado suspenso. O padrão é 0, ou iniciar o thread normalmente.
(Opcional) Os atributos de segurança desejados. O padrão é o mesmo acesso que o thread pai. Para obter mais informações sobre o formato dessas informações de segurança, consulte SECURITY_ATTRIBUTES no SDK do Windows.
AfxBeginThread
cria e inicializa um objeto CWinThread
para você, inicia-o e retorna seu endereço para que você possa se referir a ele mais tarde. São feitas verificações em todo o procedimento para garantir que todos os objetos sejam desalocados corretamente caso qualquer parte da criação falhe.
Implementando a função de controle
A função de controle define o thread. Quando essa função é inserida, o thread é iniciado e, quando ela é retirada, o thread termina. Essa função deve ter o seguinte protótipo:
UINT MyControllingFunction( LPVOID pParam );
O parâmetro é um único valor. O valor que a função recebe nesse parâmetro é o valor que foi passado para o construtor quando o objeto thread foi criado. A função de controle pode interpretar esse valor de qualquer maneira que escolher. Ele pode ser tratado como um valor escalar ou um ponteiro para uma estrutura que contém vários parâmetros ou pode ser ignorado. Se o parâmetro se referir a uma estrutura, a estrutura poderá ser usada não apenas para passar dados do chamador para o thread, mas também para passar dados do thread para o chamador. Se você usar essa estrutura para passar dados de volta para o chamador, o thread precisará notificar o chamador quando os resultados estiverem prontos. Para obter informações sobre como se comunicar do thread de trabalho para o chamador, consulte Multithreading: dicas de programação.
Quando a função for encerrada, ela deverá retornar um valor UINT que indica o motivo da terminação. Normalmente, esse código de saída é 0 para indicar êxito com outros valores que indicam diferentes tipos de erros. Isso é puramente dependente da implementação. Alguns threads podem manter contagens de uso de objetos e retornar o número atual de usos desse objeto. Para ver como os aplicativos podem recuperar esse valor, consulte Multithreading: encerrando threads.
Há algumas restrições sobre o que você pode fazer em um programa multithread escrito com a biblioteca MFC. Para obter descrições dessas restrições e outras dicas sobre como usar threads, consulte Multithreading: dicas de programação.
Exemplo de função de controle
O exemplo a seguir mostra como definir uma função de controle e usá-la de outra parte do programa.
UINT MyThreadProc( LPVOID pParam )
{
CMyObject* pObject = (CMyObject*)pParam;
if (pObject == NULL ||
!pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
return 1; // if pObject is not valid
// do something with 'pObject'
return 0; // thread completed successfully
}
// inside a different function in the program
.
.
.
pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
.
.
.