Partilhar via


Exceções entre Threads de transporte

Suporte do Visual C++ transportar uma exceção de um thread para outro.Transportar exceções permite que você capturar uma exceção em um thread e, em seguida, fazer com que a exceção pareça ser lançada em um thread diferente.Por exemplo, você pode usar esse recurso para escrever um aplicativo multi-threaded onde o thread principal lida com todas as exceções geradas pelo seus segmentos secundários.Transporte de exceções é útil principalmente para os desenvolvedores que criam sistemas ou bibliotecas de programação paralelas.Para implementar as exceções de transporte, o Visual C++ fornece a exception_ptr tipo e o current_exception, rethrow_exception, e copy_exception funções.

namespace std 
{
   typedef unspecified exception_ptr; 
   exception_ptr current_exception();
   void rethrow_exception(exception_ptr p);
   template<class E> 
       exception_ptr copy_exception(E e);
}

Parâmetros

Parâmetro

Descrição

unspecified

Uma classe interna não especificada que é usada para implementar a exception_ptr tipo.

p

Um exception_ptr objeto que faz referência a uma exceção.

E

Uma classe que representa uma exceção.

e

Uma instância do parâmetro E classe.

Valor de retorno

O current_exception função retorna um exception_ptr objeto que faz referência a exceção que está em andamento.Se nenhuma exceção está em andamento, a função retorna um exception_ptr o objeto que não está associado a qualquer exceção.

O copy_exception função retorna um exception_ptr objeto que faz referência a exceção especificada pelo e parâmetro.

Comentários

Cenário

Imagine que você deseja criar um aplicativo que pode ser dimensionado para lidar com uma quantidade variável de trabalho.Para alcançar esse objetivo, você pode projetar um aplicativo multi-threaded onde um segmento inicial, principal cria quantos segmentos secundários necessária fazer o trabalho.Os threads secundários ajudam o thread primário para gerenciar recursos, para equilibrar as cargas e melhorar a taxa de transferência.Ao distribuir o trabalho, o aplicativo multithread tem melhor desempenho que um aplicativo single-threaded.

No entanto, se um thread secundário lança uma exceção, você deseja que o thread principal para lidar com ele.Isso ocorre porque você deseja que seu aplicativo para manipular exceções de uma maneira consistente e unificada, independentemente do número de segmentos secundários.

Solução

Para lidar com a situação anterior, o padrão C++ oferece suporte a transportar uma exceção entre threads.Se um thread secundário lança uma exceção, essa exceção torna-se a exceção atual.Por analogia com o mundo real, a exceção atual é considerada em vôo.A exceção atual está em vôo desde o momento em que ela é lançada até que o manipulador de exceção que captura, ele retorna.

O thread secundário pode capturar a exceção atual em um catch bloquear e, em seguida, chame o current_exception função para armazenar a exceção em um exception_ptr objeto.O exception_ptr objeto deve estar disponível para o thread secundário e o thread principal.Por exemplo, o exception_ptr o objeto pode ser uma variável global, cujo acesso é controlado por um mutex.O termo uma exceção de transporte significa que uma exceção em um thread pode ser convertida em um formulário que pode ser acessado por outro thread.

Em seguida, o principal segmento chama o rethrow_exception função, que extrai e, em seguida, lança a exceção da exception_ptr objeto.Quando a exceção é lançada, torna-se a exceção atual no segmento primário.Ou seja, a exceção parece se originam no segmento primário.

Finalmente, o segmento principal pode capturar a exceção atual em um catch bloquear e processá-lo ou jogue a um manipulador de exceção de nível superior.Ou, o segmento principal pode ignorar a exceção e permitir que o processo terminar.

Não é necessário que a maioria dos aplicativos exceções entre threads de transporte.No entanto, esse recurso é útil em uma sistema de computação, porque o sistema pode dividir o trabalho entre os segmentos secundários, processadores ou núcleos de paralela.Em um ambiente de computação paralelo, um segmento único e dedicado pode lidar com todas as exceções dos segmentos secundários e pode apresentar um modelo consistente de manipulação de exceção para qualquer aplicativo.

Para obter mais informações sobre a proposta do Comitê de padrões de C++, pesquise na Internet para o número N2179, intitulado "Idioma suporte para transportar exceções entre Threads" do documento.

Modelos de manipulação de exceção e opções do compilador

Modelo de manipulação de exceção do aplicativo determina se ele pode capturar e uma exceção de transporte.Visual C++ oferece suporte a três modelos que podem manipular exceções C++, exceções (SEH) de manipulação de exceção estruturada e common language runtime (CLR) exceptions.Use o /EH e /clr opções de compilador para especificar o modelo de manipulação de exceção do seu aplicativo.

A seguinte combinação de opções do compilador e instruções de programação pode transportar uma exceção.Outras combinações, não é possível capturar exceções, ou pode capturar mas não pode transportar exceções.

  • O /EHa opção de compilador e o catch instrução pode transportar Exceções SEH e C++.

  • O /EHa, /EHs, e /EHsc as opções do compilador e o catch instrução pode transportar as exceções do C++.

  • O /CLR ou /CLR:pure opção de compilador e o catch instrução pode transportar as exceções do C++.O /CLR implicam na especificação de opções do compilador a /EHa opção.Observe que o compilador não suporta o transporte de exceções gerenciadas.Isso ocorre porque o gerenciado exceções, que são obtidas a System. Exception da classe, já são objetos que podem ser movidos entre threads usando os recursos do common runtime languange.

    Observação de segurançaObservação de segurança

    Recomendamos que você especifica o /EHsc opção de compilador e catch únicas exceções do C++.Você se expõe a uma ameaça de segurança se você usar o /EHa ou /CLR opção de compilador e um catch instrução com reticências declaração de exceção (catch(...)).Provavelmente você pretende usar o catch instrução para capturar algumas exceções específicas.No entanto, o catch(...) instrução captura todos os C++ e SEH exceções, inclusive as inesperadas que devem ser fatais.Se você ignorar ou mishandle uma exceção inesperada, o código mal-intencionado pode usar essa oportunidade para prejudicar a segurança do seu programa.

Uso

As seções a seguir descrevem como exceções de transporte usando o exception_ptr tipo e o current_exception, rethrow_exception, e copy_exception funções.

Dd293602.collapse_all(pt-br,VS.110).gifTipo de exception_ptr

Use um exception_ptr o objeto para fazer referência a exceção atual ou uma instância de uma exceção especificada pelo usuário.Na implementação da Microsoft, uma exceção é representada por um EXCEPTION_RECORD estrutura.Cada exception_ptr objeto inclui um campo de referência de exceção que aponta para uma cópia do EXCEPTION_RECORD estrutura que representa a exceção.

Quando você declara uma exception_ptr variável, a variável não está associada com qualquer exceção.Ou seja, o seu campo de referência de exceção é NULL.Como um exception_ptr objeto é chamado um exception_ptr nulo.

Use o current_exception ou copy_exception função para atribuir uma exceção para um exception_ptr objeto.Quando você atribui uma exceção para um exception_ptr variável, campo de referência de exceção da variável aponta para uma cópia da exceção.Se não houver memória suficiente para copiar a exceção, o campo de referência de exceção aponta para uma cópia de um std::bad_alloc exceção.Se a current_exception ou copy_exception função não é possível copiar a exceção por qualquer outro motivo, as chamadas de função do terminate (CRT) a função para sair do processo atual.

Apesar do nome, um exception_ptr objeto é um ponteiro para não propriamente dito.Ele não obedecer a semântica do ponteiro e não pode ser usado com o acesso de membro de ponteiro (->) ou operadores de indireção (*).O exception_ptr objeto não possui membros de dados públicos ou funções de membro.

Comparações:

Você pode usar o igual (==) e não-igual (!=) operadores para comparar duas exception_ptr objetos.Os operadores se compara o valor binário (padrão de bits) a EXCEPTION_RECORD estruturas que representam as exceções.Em vez disso, os operadores de comparam os endereços no campo de referência de exceção da exception_ptr objetos.Conseqüentemente, um valor nulo exception_ptr e o valor NULL comparados como iguais.

Dd293602.collapse_all(pt-br,VS.110).gifFunção de current_exception

Chamar o current_exception funcionam em um catch bloco.Se uma exceção estiver em vôo e o catch bloco pode capturar a exceção, o current_exception função retorna um exception_ptr objeto que faz referência a exceção.Caso contrário, a função retorna um valor nulo exception_ptr objeto.

Detalhes

O current_exception função captura a exceção que está em trânsito, independentemente se a catch declaração especifica um declaração de exceção instrução.

O destruidor para a exceção atual é chamado no final do catch bloquear se você não relançar a exceção.No entanto, mesmo se você chamar o current_exception função de destruidor, ofunção retorna um exception_ptr objeto que faz referência a exceção atual.

Chamadas sucessivas para o current_exception função de retorno exception_ptr objetos que fazem referência a cópias diferentes da exceção atual.Conseqüentemente, os objetos comparam como desigual porque eles se referem a cópias diferentes, mesmo que as cópias tiverem o mesmo valor binário.

Exceções SEH:

Se você usar o /EHa opção de compilador, você pode capturar uma exceção SEH em um C++ catch bloco.O current_exception função retorna um exception_ptr objeto que faz referência a exceção SEH.E o rethrow_exception função lança a exceção SEH, se você chamá-lo com otransportado exception_ptr o objeto como seu argumento.

O current_exception função retorna um valor nulo exception_ptr se você chamá-la em um SEH __finally manipulador de terminação, um __except o manipulador de exceção, ou o __except expressão de filtro.

Uma exceção transportada não oferece suporte a exceções aninhadas.Uma exceção aninhada ocorre se a outra exceção é lançada, enquanto uma exceção está sendo manipulada.Se você capturar uma exceção aninhada, o EXCEPTION_RECORD.ExceptionRecord membro de dados aponta para uma cadeia de EXCEPTION_RECORD estruturas que descrevem as exceções associadas.O current_exception função não oferece suporte a exceções aninhadas porque ele retorna um exception_ptr de objeto cuja ExceptionRecord membro de dados é zerado.

Se você capturar uma exceção SEH, você deve gerenciar a memória referenciada por qualquer ponteiro na EXCEPTION_RECORD.ExceptionInformation matriz de membro de dados.Você deve garantir que a memória é válida durante a vida útil do correspondente exception_ptr objeto e que a memória é liberada quando o exception_ptr objeto é excluído.

Você pode usar as funções de conversor de exceção estruturada (SE) juntamente com o recurso de exceções de transporte.Se uma exceção SEH for convertida em uma exceção de C++, o current_exception função retorna um exception_ptr que faz referência a exceção traduzida em vez da exceção SEH original.O rethrow_exception função subseqüentemente lança a exceção traduzida, não a exceção original.Para obter mais informações sobre as funções do Sudeste do conversor, consulte set_se_translator.

Dd293602.collapse_all(pt-br,VS.110).gifFunção de rethrow_exception

Depois de armazenar uma exceção identificada em um exception_ptr de objeto, o segmento principal pode processar o objeto.No seu segmento principal, chame o rethrow_exception funcionam em conjunto com o exception_ptr o objeto como seu argumento.O rethrow_exception função extrai a exceção da exception_ptr de objeto e, em seguida, lança a exceção no contexto do thread principal.Se a p parâmetro da rethrow_exception função é um valor nulo exception_ptr, a função lança std::bad_exception.

A exceção extraída agora é a exceção atual no thread principal e você possa tratá-la como faria com qualquer outra exceção.Se você capturar a exceção, você pode manipulá-lo imediatamente ou usar um throw instrução para enviá-lo para um manipulador de exceção de nível superior.Caso contrário, não faça nada e deixar que o manipulador de exceção padrão do sistema terminar o processo.

Dd293602.collapse_all(pt-br,VS.110).gifFunção de copy_exception

O copy_exception função obtém uma instância de uma classe como seu argumento e retorna um exception_ptr que faz referência a instância.Normalmente, você especifica um classe de exceção o objeto como argumento para o copy_exception funcionar, embora qualquer objeto de classe pode ser o argumento.

Chamar o copy_exception função é equivalente a gerar uma exceção de C++, detectá-lo em um catch bloco e depois chamar o current_exception função para retornar um exception_ptr objeto que faz referência a exceção.A implementação da Microsoft a copy_exception função é mais eficiente que lançando e, em seguida, captura uma exceção.

Um aplicativo normalmente não exige a copy_exception função e podemos desencorajar seu uso.

Exemplo

O exemplo a seguir transporta uma exceção de C++ padrão e uma exceção de C++ personalizada de um thread para outro.

// transport_exception.cpp
// compile with: /EHsc /MD
#include <windows.h>
#include <stdio.h> 
#include <exception>
#include <stdexcept>

using namespace std;

// Define thread-specific information.
#define THREADCOUNT 2
exception_ptr aException[THREADCOUNT]; 
int           aArg[THREADCOUNT];

DWORD WINAPI ThrowExceptions( LPVOID ); 

// Specify a user-defined, custom exception. 
// As a best practice, derive your exception 
// directly or indirectly from std::exception. 
class myException : public std::exception { 
};
int main()
{
    HANDLE aThread[THREADCOUNT];
    DWORD ThreadID;

    // Create secondary threads.
    for( int i=0; i < THREADCOUNT; i++ )
    {
        aArg[i] = i;
        aThread[i] = CreateThread( 
            NULL,       // Default security attributes.
            0,          // Default stack size.
            (LPTHREAD_START_ROUTINE) ThrowExceptions, 
            (LPVOID) &aArg[i], // Thread function argument.
            0,          // Default creation flags.
            &ThreadID); // Receives thread identifier.
        if( aThread[i] == NULL )
        {
            printf("CreateThread error: %d\n", GetLastError());
            return -1;
        }
    } 

    // Wait for all threads to terminate.
    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE); 
    // Close thread handles.
    for( int i=0; i < THREADCOUNT; i++ ) {
        CloseHandle(aThread[i]); 
    }

    // Rethrow and catch the transported exceptions.
    for ( int i = 0; i < THREADCOUNT; i++ ) {
        try {
            if (aException[i] == NULL) {
                printf("exception_ptr %d: No exception was transported.\n", i);
            }
            else {
                rethrow_exception( aException[i] );
            }  
        }
        catch( const invalid_argument & ) {
            printf("exception_ptr %d: Caught an invalid_argument exception.\n", i);
        }
        catch( const myException & ) {
            printf("exception_ptr %d: Caught a  myException exception.\n", i);
        }
    }
} 
// Each thread throws an exception depending on its thread 
// function argument, and then ends. 
DWORD WINAPI ThrowExceptions( LPVOID lpParam ) 
{ 
    int x = *((int*)lpParam);
    if (x == 0) {
        try {
            // Standard C++ exception.
            // This example explicitly throws invalid_argument exception. 
            // In practice, your application performs an operation that 
            // implicitly throws an exception.
            throw invalid_argument("A C++ exception.");
        }  
        catch ( const invalid_argument & ) { 
            aException[x] = current_exception();
        } 
    }
    else {
        // User-defined exception.
        aException[x] = copy_exception( myException() ); 
    }
    return TRUE; 
}
  
  

Requisitos

Cabeçalho: <exception>

Consulte também

Referência

Tratamento de exceção no Visual C++

Estrutura EXCEPTION_RECORD

sintaxe de manipulador

/EH (modelo de manipulação de exceção)

/CLR (common Language Runtime Compilation)