Contextos
Este documento descreve a função de contextos no Runtime de Simultaneidade. Um thread anexado a um agendador é conhecido como um contexto de execução ou apenas contexto. A função concurrency::wait e a classe concurrency::Context permitem que você controle o comportamento dos contextos. Use a função wait
para suspender o contexto atual por um tempo especificado. Use a classe Context
quando precisar de mais controle sobre quando os contextos bloqueiam, desbloqueiam e suspendem ou quando desejar assinar o contexto atual.
Dica
O Runtime de Simultaneidade fornece um agendador padrão e, portanto, você não precisa criar um em seu aplicativo. Como o Agendador de Tarefas ajuda você a ajustar o desempenho de seus aplicativos, é recomendável que você comece com a PPL (Biblioteca de Padrões Paralelos) ou a Biblioteca de Agentes Assíncronos se você for novo no Runtime de Simultaneidade.
A Função wait
A função concurrency::wait produz cooperativamente a execução do contexto atual para um número especificado de milissegundos. O runtime usa o tempo de rendimento para executar outras tarefas. Depois que o tempo especificado tiver decorrido, o runtime reagenda o contexto para execução. Portanto, a função wait
pode suspender o contexto atual por mais tempo do que o valor fornecido para o parâmetro milliseconds
.
Passar 0 (zero) para o parâmetro milliseconds
faz com que o runtime suspenda o contexto atual até que todos os outros contextos ativos recebam a oportunidade de executar o trabalho. Isso permite que você produza uma tarefa para todas as outras tarefas ativas.
Exemplo
Para obter um exemplo que usa a função wait
para produzir o contexto atual e, portanto, permitir a execução de outros contextos, consulte Como usar grupos de agendamento para influenciar a ordem de execução.
A classe Context
A classe concurrency::Context fornece uma abstração de programação para um contexto de execução e oferece dois recursos importantes: a capacidade de bloquear, desbloquear e produzir cooperativamente o contexto atual e a capacidade de assinar o contexto atual.
Bloqueio cooperativo
A classe Context
permite que você bloqueie ou produza o contexto de execução atual. O bloqueio ou o rendimento são úteis quando o contexto atual não puder continuar porque um recurso não está disponível.
O método concurrency::Context::Block bloqueia o contexto atual. Um contexto bloqueado gera seus recursos de processamento para que o runtime possa executar outras tarefas. O método concurrency::Context::Unblock desbloqueia um contexto bloqueado. O método Context::Unblock
deve ser chamado de um contexto diferente daquele chamado Context::Block
. O runtime gera concurrency::context_self_unblock se um contexto tentar desbloquear a si mesmo.
Para bloquear e desbloquear um contexto de forma cooperativa, normalmente você chama concurrency::Context::CurrentContext para recuperar um ponteiro para o objeto Context
associado ao thread atual e salvar o resultado. Em seguida, você chama o método Context::Block
para bloquear o contexto atual. Posteriormente, chame Context::Unblock
de um contexto separado para desbloquear o contexto bloqueado.
Você deve corresponder a cada par de chamadas para Context::Block
e Context::Unblock
. O runtime gera concurrency::context_unblock_unbalanced quando o método Context::Block
ou Context::Unblock
é chamado consecutivamente sem uma chamada correspondente para o outro método. No entanto, você não precisa chamar Context::Block
antes de chamar Context::Unblock
. Por exemplo, se um contexto chamar Context::Unblock
antes de outro contexto chamar Context::Block
para o mesmo contexto, esse contexto permanecerá desbloqueado.
O método concurrency::Context::Yield gera execução para que o runtime possa executar outras tarefas e, em seguida, reagendar o contexto para execução. Quando você chama o método Context::Block
, o runtime não reagenda o contexto.
Exemplo
Para obter um exemplo que usa os métodos Context::Block
, Context::Unblock
e Context::Yield
para implementar uma classe de semáforo cooperativa, consulte Como usar a classe de contexto para implementar um semáforo cooperativo.
Excesso de assinatura
O agendador padrão cria o mesmo número de threads que o número de threads de hardware disponíveis. Você pode usar excesso de assinatura para criar threads adicionais para um determinado thread de hardware.
Para operações computacionalmente intensivas, o excesso de assinatura normalmente não é dimensionado porque introduz sobrecarga adicional. No entanto, para tarefas que têm uma alta quantidade de latência, por exemplo, ler dados de disco ou de uma conexão de rede, o excesso de assinatura pode melhorar a eficiência geral de alguns aplicativos.
Observação
Habilite o excesso de assinatura somente de um thread que tenha sido criado pelo Runtime de Simultaneidade. O excesso de assinatura não tem efeito quando é chamado de um thread que não tenha sido criado pelo runtime (incluindo o thread principal).
Para habilitar o excesso de assinatura no contexto atual, chame o método concurrency::Context::Oversubscribe com o _BeginOversubscription
parâmetro definido como true
. Quando você habilita o excesso de assinatura em um thread criado pelo Runtime de Simultaneidade, ele faz com que o runtime crie um thread adicional. Após todas as tarefas que exigem a conclusão do excesso de assinatura, chame Context::Oversubscribe
com o parâmetro _BeginOversubscription
definido como false
.
Você pode habilitar o excesso de assinatura várias vezes no contexto atual, mas deve desabilitar o mesmo número de vezes que habilitá-lo. O excesso de assinatura também pode ser aninhado; ou seja, uma tarefa criada por outra tarefa que use excesso de assinatura também pode assinar em excesso seu contexto. No entanto, se uma tarefa aninhada e seu pai pertencerem ao mesmo contexto, apenas a chamada Context::Oversubscribe
mais externa causará a criação de um thread adicional.
Observação
O runtime gera concurrency::invalid_oversubscribe_operation se o excesso de assinatura estiver desabilitado antes de ser habilitado.
Exemplo
Para obter um exemplo que usa o excesso de assinatura para compensar a latência causada pela leitura de dados de uma conexão de rede, consulte Como usar o excesso de assinatura para compensar a latência.
Confira também
Agendador de Tarefas
Como usar grupos agendados para influenciar a ordem de execução
Como usar a classe de contexto para implementar um semáforo cooperativo
Como usar excesso de assinatura para compensar a latência