Multithreading: Como usar as classes de sincronização
Sincronizar acesso a recursos entre threads é um problema comum ao escrever aplicativos multissegmentados.Ter dois ou mais threads simultaneamente os mesmos dados podem levar a resultados indesejáveis e imprevisíveis de acesso.Por exemplo, um thread pode estar atualizando o Sumário de uma estrutura enquanto outro thread está lendo o Sumário da mesma estrutura.Ele é desconhecido que receberá o thread de leitura de dados: os dados antigos, os dados recém-gravados ou possivelmente uma mistura de ambos.MFC fornece uma série de sincronização e classes de acesso de sincronização para ajudar na solução do problema.Este tópico explica as classes disponível e como usá-los para criar classes de thread-safe em um aplicativo multithreaded típico.
Um aplicativo multithreaded típico tem uma classe que representa um recurso seja compartilhado entre segmentos.Uma classe projetada corretamente totalmente thread-safe não requer que você chame quaisquer funções de sincronização.Tudo o que é tratado internamente para a classe, permitindo que você se concentrar em como melhor uso da classe, não sobre como pode obter corrompido.Uma técnica efetivo para criação de uma classe totalmente segura para thread é a classe de sincronização mesclagem com a classe de recurso.Mesclando as classes de sincronização a classe compartilhada é um processo simples.
sistema autônomo Por exemplo, colocar um aplicativo que mantém uma lista vinculada de contas.Este aplicativo permite que até três contas a ser examinado em janelas separadas, mas somente um pode ser atualizado no qualquer determinado time.Quando uma conta for atualizada, os dados atualizados são enviados pela rede para um arquivar de dados.
Este aplicativo exemplo usa os três tipos de classes de sincronização.Porque ela permite que até três contas a ser examinado ao mesmo time, ele usa CSemaphore para limitar o acesso aos três objetos de exibição.Quando uma tentativa de ler de uma quarta conta ocorre, o aplicativo seja aguarda até que um dos fecha primeiro três janelas ou ele falhar.Quando uma conta for atualizada, o aplicativo usa CCriticalSection para garantir que apenas uma conta é atualizado ao mesmo time.Após a atualização for bem-sucedida, ele sinaliza CEvent, que lança um thread aguardando o evento ser sinalizado.Esse thread envia os dados novos para o arquivar de dados.
Criando uma classe thread-safe
Para tornar uma classe totalmente thread-safe, adicione primeiro a classe de sincronização apropriado para sistema autônomo classes compartilhadas sistema autônomo um membro de dados.No exemplo de gerenciamento de conta anterior, um CSemaphore membro de dados seria adicionado à classe modo de exibição, um CCriticalSection membro de dados seria adicionado à classe lista vinculada e um CEvent membro de dados seria adicionado à classe de armazenamento de dados.
Em seguida, adicionar chamadas de sincronização para todas as funções de membro que modificam os dados na classe ou acesso um recurso controlado.Em cada função, você deve criar qualquer um CSingleLock or CMultiLock objeto e telefonar que o objeto 's Lock função. Quando o objeto de bloquear sai do escopo e é destruído, o destruidor do objeto chama Unlock para você, liberando o recurso. Obviamente, você pode chamar Unlock diretamente se desejar.
Projetar sua classe thread-safe dessa maneira permite que ele seja usado em um aplicativo multithreaded sistema autônomo com com facilidade sistema autônomo uma classe não seguro para thread, mas com um nível mais alto de segurança.O objeto de sincronização e o objeto de sincronização de acesso de encapsulamento para classe do recurso fornece todos os benefícios da programação thread-safe totalmente sem o inconveniente de manutenção do código de sincronização.
O exemplo de código a seguir demonstra esse método por meio de um membro de dados, m_CritSection (do tipo CCriticalSection), declarado na classe de recurso compartilhado e um CSingleLock objeto. A sincronização do recurso compartilhado (derivado de CWinThread) é tentada pela criação de um CSingleLock usando o endereço do objeto a m_CritSection objeto. É feita uma tentativa de bloquear o recurso e, quando obtido, o trabalho é concluído no objeto compartilhado.Quando o trabalho for concluído, o recurso está desbloqueado com uma telefonar para Unlock.
CSingleLock singleLock(&m_CritSection);
singleLock.Lock();
// resource locked
//.usage of shared resource...
singleLock.Unlock();
Observação: |
---|
CCriticalSection, ao contrário de outras classes de sincronização do MFC, não tem a opção de uma solicitação de bloquear com tempo. O período de espera para um segmento fique disponível é infinito. |
As desvantagens dessa abordagem são que a classe será um pouco mais lenta do que a mesma classe sem os objetos de sincronização adicionados.Além disso, se houver uma chance de que mais de um thread pode excluir o objeto, a abordagem mesclada pode nem sempre funcionar.Nessa situação, é melhor manter objetos de sincronização separado.
Para obter informações sobre como determinar qual classe de sincronização para usar em situações diferentes, consulte Multithreading: Quando usar a sincronização classes.Para obter mais informações sobre a sincronização, consulte Sincronização in the Windows SDK. Para obter mais informações sobre o suporte a multithreading no MFC, consulte Multithreading com C++ e do MFC.