Baixe o app para aproveitar ainda mais
Prévia do material em texto
Memória Transacional MO601- Arquitetura de Computadores II Walisson F. Pereira1 1Instituto de Computação – Universidade Estadual de Campinas Av. Albert Einstein, 1251 – 13083-850 Campinas, SP walisson@ic.unicamp.br Abstract. Parallel computing has enabled a considerable performance gain in the programs’ execution, dividing them into smaller pieces and concurrently sol- ving them using multiple computational resources. This approach has brought several benefits compared to sequential programming, allowing solve increasin- gly complex and time dwindling. The transactional memory has emerged as a new proposal for multiprocessor architecture that supports implementing lock- free complex data structures in a simple and efficient way. In this work, we discussed some basic concepts of transactional memory giving a quick overview of some design alternatives that can be adopted. Resumo. A computação paralela permitiu um considerável ganho de desempe- nho na execução dos programas, dividindo-os em partes menores e resolvendo- as concorrentemente usando múltiplos recursos computacionais. Essa abor- dagem trouxe uma série de benefı́cios em relação a programação sequencial, permitindo resolver problemas cada vez mais complexos e em tempo cada vez menor. A memória transacional surgiu como uma nova proposta de arquitetura multiprocessada que suporta a implementação lock-free de estruturas de dados complexas de uma forma simples e eficiente. Nesse trabalho é discutido alguns conceitos básicos das memória transacional dando uma rápida visão geral so- bre algumas alternativas de projeto que podem ser adotadas. 1. Introdução A memória transacional, do inglês Transactional Memory (TM), é uma nova arquitetura multiprocessada que suporta a implementação lock-free de estruturas de dados comple- xas de uma forma simples e eficiente [Herlihy and Moss, 1993]. Uma estrutura é dita lock-free se as operações definidas para ela não requerem exclusão mútua sobre multi- plas instruções [Culler et al., 1999], ou seja, se um processo é interrompido no meio da operação, outros processos não serão impedidos de operarem nessa estrutura. As estruturas de dados lock-free evitam problemas comuns associados as técnicas de locks convencionais em sistemas altamente concorrentes: • Inversão de prioridade: ocorre quando um processo de baixa prioridade é adqui- rido por preempção enquando mantém um lock necessário pelos processos de alta prioridade. • Proteção: ocorre quando um processo matém um lock e é substituı́do pelo escalo- nador, talvez por ultrapassar seu quantum, por uma falha de página, ou por algum tipo de interrupção. Quando tal interrupção ocorre, outros processos capazes de rodarem podem ficar ináptos de progredir. • Deadlock: pode ocorrer se os processos tentarem travar o mesmo conjunto de objetos em ordens diferentes. Evitar Deadlock pode ser ineficaz se os processos puderem travarem multiplos objetos de dados, particularmente se o conjunto de objetos não forem conhecidos de antemão. As TM permite os programadores definirem operações read-modify-write perso- nalizadas que aplicam a múltiplas e independetes palavras escolhidas da memória. Ela é implementada por extensões diretas para algum protocolo de coerência de cache multi- processada baseada em propriedade. O conceito de transação originou-se na literatura de banco de dados [Gray, 1978], e de acordo com [Harris et al., 2010], uma transação é uma sequência de ações que pare- cem indivisı́veis e instantâneas para um observador externo. Em outras palavras, quando uma transação termina corretamente, diz-se que ela efetiva-se (do inglês, commit), ou caso ela falhe, então a transação é abortada e nenhuma de suas ações é visı́vel. Uma transação satisfaz as seguintes propriedades: • Serialização: transações aparentam ser executadas serialmente, significando que cada passo de uma transação nunca aparenta ser entrelaçada com o passo de outra. Transações concluı́das nunca são observada por processadores diferentes execu- tando em ordens diferentes. • Atomicidade: cada transação realiza uma sequência de tentativa de mudanças na memória compartilhada. Quando a transação completa, ela, então, se efetiva, fa- zendo suas mudanças visı́veis para os outros processos (efetivamente) instantane- amente, ou então, ela aborta, fazendo suas mudanças serem descartadas. A memória transacional é um mecanismo que promete habilitar desempenho es- calável enquanto libera os programadores de alguns encargos para modificar seus códigos paralelos. Os modelos de programação multithreads tradicionais geralmente oferecem um conjunto de primitivas de baixo nı́vel, como locks, para garantir a exclusão mútua. Os Locks são complexos para se usar e propenso a erros – especialmente quando um programador está tentando evitar situações de deadlock ou alcançar melhor escalabili- dade em hardware altamente paralelos usando um lock de granulação refinada. Nesse cenário, a TM é um mecanismo promissor para lidar com este problema através da abstração das complexidades associadas com o acesso concorrente de dados comparti- lhados [Larus and Rajwar, 2007]. Entretanto, apesar de usar mecanismos similares as transações de banco de dados clássicos, o principal propósito da TM é diferente: lidar com os desafios da concorrência na memória compartilhada em chips com multiproces- sadores. As transações substituem os locks com unidades de execuções atômicas, tal que o programador pode focar em determinar onde a atomicidade é necessária, ao invés de se preocupar nos mecanismos que a reforçará. Com essa abstração, o programador identifica as operações que formam a seção crı́tica, enquanto a implementação da TM determina como rodar esta seção crı́tica de forma isolada de outros threads. Geralmente, o termo “conflito” significam uma violação na ordem temporal e “prévio” é usado no sentido da ordenação temporal [Harris et al., 2010]. Se as transações não conflitam, então abordagens otimistas vale a pena. Como o exemplo de uma transação que realiza apenas acessos somente para leitura de dados compartilhados e permite que to- dos os dados possam permanecer nas caches de dados no modo compartilhado, ajudando a escalabilidade. Se as transações tentarem realizar acessos conflitante, então o otimismo não vale a pena. Nesse caso, a TM deve abandonar o trabalho de uma das transações conflitantes, garantindo que nenhum efeito colateral dessa tentativa seja visı́vel para outras threads, antes de reexecutar a transação abandonada. Comparado com a TM, os locks são abordagens pessimistas. Com os locks de exclusão múltua, apenas uma thread pode ter o lock para si por vez, enquanto que a maioria das implementações de TM, mais que uma thread pode acessar uma seção crı́tica simultaneamente. Devido os conflitos atuais serem raros em muitos programas, abordagens de TM otimistas fazem mais sentido como um modelo de programação futuro [Harris et al., 2007]. As vantagens da TM sobre os locks são: • A TM provém uma abstração de alto nı́vel para a escrita de programas concorren- tes; • A TM provém um melhor trade-off entre escalabilidade e esforço de implementação; • A TM é inerentemente livre de deadlock; • A TM provém atomicidade de falha. As desvantagens da TM são: • Devido a abstração de alto nı́vel, um algoritmo cuidadosamente projetado usando primitivas de baixo nı́vel pode superar o desempenho de um algorı́tmo usando TM; • Existem muitas questões sobre como expor a TM aos programadores: exatamente que tipo de abstração prover e que tipo de ajuste de desempenho e ferramentas de depuração desenvolver. O foco deste trabalho é apresentar uma visão geral sobre memória transacional. A seção 2 apresenta uma visão geral sobre as transações em bancos de dados; a seção 3 apresenta alguns conceitos básicos da TM; a seção4 apresenta os tipos principais de implementação da TM; a seção 5 ilustra alguns dos desafios de se projetar uma TM; e, por último, a seção 6 conlui o trabalho com algumas considerações finais. 2. Transações em banco de dados Apesar do paralelismo ser um problema difı́cil para a programação de propósito geral, dependendo muito do programador, os bancos de dados conseguem explorá-lo de maneira satisfatória. As TM compartilham muitas caracterı́sticas em comum com as transações de banco de dados, da terminologia e similaridades sintáticas até as propriedades que elas provêm [Felber et al., 2008]. O controle de concorrência tem sido estudado por décadas no campo dos sistemas de banco de dados, onde operações diferentes podem acessar tabelas simultanemantes sem observar-se interferência. Transações são um mecanismo poderoso para gerenciar tais acessos concorrtes a um banco de dados. As transações garantêm as quatro propriedades denominadas ACID: • Atomicidade: uma transação executa completamente ou não executa; • Consistência: as transações são uma transformação correta de estado; • Isolamento: apesar das transações executarem concorrentemente, aparenta que para cada transação T que outras transações executam tanto antes de T ou depois de T , mas não ao mesmo tempo; • Durabilidade: modificações realizadas por transações completadas sobrevivem às falhas. Este comportamento é implementado pelo controlador para acessar dados compartilhados e desfazer as ações de uma transação que não completou com sucesso (roll-back) 3. Memória transacional Diferentemente das transações de bancos de dados, as transações de memória são pla- nejadas para serem atividades de curta duração que acessam um número relativamente pequeno de locais na memória principal. O tamanho e duração ideal de uma transação é dependente da implementação, mas, de modo geral, uma transação deve ser apta a rodar completamente em um simples quantum de escalonamento, e o número de locais acessa- dos não deve exceder ao tamanho da cache do processador. Uma transação em TM é definida como uma sequência de instruções, incluindo leituras e escritas à memória, que ou executa completamente (efetiva-se) ou que não te- nha efeito (aborta-se). Quando uma transação efetiva, todas as suas escritas tornam-se visı́veis, e outras transações podem usar esses valores. Quando uma transação aborta, o sistema descarta todas as suas escritas especulativas. Para isso, o sistema de TM precisa de um mecanismo de versionamento de dados para gravar suas escritas especulativas. As duas abordagens mais utilizadas para implementar o versionamento de dados são: o undo log e o buffered updates. No undo log, uma transação aplica atualizações diretamente no endereço de memória, enquanto escreve um log com as informações ne- cessárias para desfazer as atualizações no caso precise abortar. No buffered update, a TM mantém o estado especulativo da transação num buffer privado até o momento de sua efetivação. Se a efetivação ocorre, os valores originais são descartados e o conteúdo do buffer é efetivado na memória. Uma sequência de instruções de transação podem ser delimitadas explicitamente ou implicitamente. É demilitada explicitamente quando tokens especiais são utiliza- dos para indicar o inı́cio e o fim da transação, por exemplo, START TRANSACTION e END TRANSACTION. A transação é dita ser delimitada implicitamente quando ela é ini- ciada implicitamente após a execução de uma operação de leitura ou escrita transacional ou imediatamente após a efetivação de outra transação no fluxo de instruções. Um sistema de TM pode abortar transações explicitamente, através da execução de uma instrução de abortar, ou implicitamente, devido a conflitos de dados com transações concorrentes. Duas questões estão relacionadas a conflitos: detecção e resolução. Para detectar e lidar com conflitos, cada transação é associada a um conjunto de leituras e um conjunto de escritas. Dentro da transação, a execução de cada instrução de leitura transacional adici- ona o endereço de memória ao conjunto de leitura. Cada instrução de escrita transacional adiciona o endereço de memória e o valor no conjunto de escrita. A detecção de conflitos pode ser ansiosa ou preguiçosa. A detecção ansiosa veri- fica todas as leituras e escritas individualmente para ver se há uma operação conflitante com outra transação. A detecção de conflitos ansiosa requer os conjuntos de leitura e es- crita de uma transação seja visı́veis para todas as outras transações no sistema. A detecção preguiçosa espera até que a transação tente se efetivar para checar seus conjuntos de lei- tura e escrita com outros conjuntos de escritas de outras transações. A figura 1 mostra a linha de tempo da execução de dois pares de transações. Os dois métodos de detecção de conflitos detectam um conflito no primeiro par de transações (a). No segundo par de transações (b), o método de detecção de conflitos ansioso detecta o conflito, mas o método preguiçoso permitirar que ambas as transações se efetivem. Isso ocorre porque em ambas as sequências, o método de detecção de conflitos ansioso detecta o conflito na leitura do endereço X por T1, pois T2 já tinha escrito no endereço X . Na figura 1a, o método de detecção de conflitos preguiçoso detecta um conflito porque T2 tenta efetivar primeiro, implicando que T1 deveria ter usado o resultado da escrita de T2. Na figura 1b, tanto T1 quanto T2 efetivam-se, pois T1 efetiva-se primeiro, e seu acesso a leitura não precisa usar o resultado da escrita de T2. Figura 1: Linha de tempo da execução de dois pares de transações [Harris et al., 2010]. Diferentes sistemas de TM detectam conflitos em diferentes nı́veis de granulari- dade. Podem ser a nı́vel de objetos, como vetores ou listas, como podem ser granularidade menores como campos individuais de uma estrutura de dados ou linhas de cache. Depen- dendo da escolha, podemos ter trade-offs baseados em ganhos de desempenho em relação ao tempo, sobrecarga de espaço de armazenamento e false sharing. Outro problema das TM é como resolver os conflitos uma vez que eles foram de- tectados. A ação mais comum é abortar umas das transações envolvidas, porém a decisão de qual transação deve ser abortada é complexa. A figura 2 ilustra as linhas de tempo de três transações. Considerando que o sis- tema de TM usa a detecção de conflitos ansiosa. Quando T1 realiza a leitura no endereço X , o sistema detecta um conflito com a escrita no endereço X da transação T2, e uma transação deve ser abortada. Agora, se a polı́tica de resolução de conflitos decidir abortar T2, depois T1 irá conflitar novamente com T3, e outra transação precisará ser abortada. Entretanto, se a polı́tica de resolução de conflitos decidir abortar T1, tanto T2 quanto T3 poderão concluir, e apenas uma única transação precisou ser abortada. Outros dois conceitos importantes em TM são bloqueio e escolha. Bloqueio é um mecanismo que explicitamente que aborta uma transação. Escolha é um conjunto de ações transacionais empreendias como uma alternativa ao bloqueio. 4. Tipos de implementações de TM Existem dois principais estilos de implementação de TM: baseado em hardware e baseado em software. 4.1. Memória transacional baseada em hardware A memória transacional baseada em hardware, do inglês Hardware Transactional Memory (HTM), foi historicamente o primeiro projeto de TM proposto. Em geral, para implementar a HTM, duas modificações são suficientes [Harris et al., 2010]: • Modificar o protocolo de coerência de cache; • Complementar o conjunto de instruções da arquitetura com um pequeno grupo de novas instruções. Figura 2: Linha de tempo da execução de três transações [Harris et al., 2010]. O sistema TMmantém o estado especulativo em uma cache extra, ou um buffer, até que a transação seja efetivada ou aborte. As adições do conjunto de instruções da arquitetura podem envolver duas instruções para delimitar a transação: Start TRansaction (STR) e End TRansaction (ETR). Além de versões especiais das instruções de leitura e escrita, como Transactional LoaD (TLD) e Transactional STore (TSD) são necessárias. As adições também podem englobar instruções especiais para abortar (ABR) e validar (VLD). Essas duas últimas instruções permitem algumas otimizações: O ABR permite que um controle de programa possar se- lecionar uma transação vı́tima em caso de conflito; O VLD permite poupar energia. Uma transação bastante longa pode se beneficiar com essa instrução por não precisar executar- se até o fim no caso de um conflito precoce, podendo abortar precocemente e retornando ao estado inicial. O versionamento da dados, geralmente, usa a cache ou um buffer de modificações. Os sistemas HTM mantêm o estado das transações especulativas principalmente na cache de dados ou num buffer. As HTM trabalham com granularidades de palavras ou linhas de cache. As leituras e escritas transacionais ficam em uma cache separada, ou na cache de dados convencional aumentada para o suporte transacional [Herlihy and Moss, 1993]. Nesse caso, as modificações são mı́nimas porque o suporte transacional confia em es- tender algum protocolo de coerência de cache existente (como o MESI) para detectar conflitos e reforçar atomicidade. 4.2. Memória Transacional baseada em Software A memória transacional por software, do inglês Software Transactional Memory (STM), [Shavit and Touitou, 1995] é uma variante da memória transacional [Herlihy and Moss, 1993]. Nesta seção, olhamos o caso básico de transações não aninhadas que atualizam a memória compartilhada dentro de um único processo mul- tithread, focando nos problemas principais que um STM deve lidar: Prover uma visão separada por thread das pilhas a qual as transações executam, e prover mecanismos para detectar e resolver conflitos entre transações. A implementação de uma STM deve prover seu próprio mecanismo de transações concorrentes para gerenciar suas próprias visões da pilha. Desta forma um mecanismo permite uma transação ver suas próprias escritas enquanto continua a rodar e permite que atualizações da memória sejam descartadas se a transação, no final, abortar. As STM podem ser caracterizadas por sua organização de memória. Uma pri- meira abordagem pode separar os dados transacionais dos dados normais, introduzindo um formato de memória distinta para objetos transacionais. Enquanto outra abordagem pode permitir que os dados mantenham sua estrutura de dados normais, e o STM usa estruturas separadas para gerenciar suas próprias metadados. A implementação da STM usa o cabeçalho do objeto para traçar com quais transações estão acessando concorrentemente o objeto. A interface de programação da aplicação, do inglês Application Programming Interface (API), deve diferenciar acessos de leituras e escritas devido múltiplas transações concorrentes poderem compartilhar o mesmo corpo de objeto durante o perı́odo que todas estão apenas realizando leitura. Se uma transação precisar atualizar um objeto, o comando OpenForWriting retorna uma cópia sombra do corpo do objeto. A Object-based STM (OSTM) [Fraser, 2004] mantém em tempo de execução um conjunto de leituras com os objetos que uma transação lê e um conjunto de escrita com os objetos que são atualizados. Abortar uma transação simplesmente significa descartar alguma cópia sombra que foi criada para a escrita. Efetivar uma transação significa: 1. Atomicamente checar que nenhuma transação conflitante tenha atualizado o ob- jeto no conjunto de leituras ou escrita, e; 2. Atualizar o cabeçalho do objeto para o objeto no conjunto de escrita, desta forma publicando a cópia sombra privada como o novo conteúdo do objeto. O sistema STM Bartok [Harris et al., 2006] não faz distinção de baixo nı́vel entre dados normais de transacionais. Esta implementação matém o metadado que a STM usa para o controle de concorrência em estruturas separadas, com a STM usando uma função para mapear uma palavra de endereço para uma palavra do metadado transacional que gerencia estes dados. Há várias maneiras de implementar as API da STM. Nos projetos que usam buf- fered updates, uma transação mantém uma cópia sombra privada de todas as palavras da memória que ela atualizou, quase como uma HTM mantém cópias privadas delas em sua cache de dados locais. Uma leitura deve consultar a cópia sombra e então ver se há es- critas recentes da mesma transação. Outra alternativa de projeto usa atualizações in loco. O comando de escrita transacional atualiza diretamente a pilha para que então chama a leitura transacional que verá as atualizações recentes sem precisar procurar numa tabela. Nesse caso, a escrita transacional deve manter uma undo log de todos os valores que ela sobrescreveu. A desvantagem dessa abordagem é que ela pode introduzir contenção entre as transações, pois apenas uma transação pode ganhar o acesso à escrita ao mesmo tempo. Diferentemente da HTM, a detecção e resolução de conflitos na implementação STM tende a ser mais complicada, pois apenas ações individuais de operações de memória são atômicas. Contudo, existem várias abordagens a serem exploradas: Esquemas pes- simista baseados em travar automaticamente dados que as transações estão acessando, esquema otimistas não bloqueante, e vários outros esquemas hı́bridos. Uma abordagem usada em [Liskov, 1988] emprega duas fases rigorosas de trava de objetos. Um compilador pode prontamente automatizar essa abordagem, no qual ad- quirir locks como uma transação executa e mantê-lo até sua efetivação. Porém, essa abor- dagem têm péssima escalabilidade em processadores multiprocessados atuais por intro- duzir contenção na hierarquia de memória. Uma alternativa é usar uma atualização atômica, não bloqueante e multipalavra para efetivar a transação. O OSTM faz isso através da realização de uma atualização de várias palavras atômica em todo o conteúdo do cabeçalho dos objetos nos conjuntos de leitura e escrita. A vantagem desse método é permitir uma melhor escalabilidade de leitura transacional. Outros trabalhos anteriores frequentemente miravam no comportamento não blo- queante como uma meta explı́cita, pois um algoritmo não bloqueante garante que o pro- gresso do programa não seja obstruı́do por threads que não estão executando ativamente. Isso evita também problemas como inversão de prioridade ou de threads serem descalo- nados enquanto mantém um lock. 4.3. Memória transacional hı́brida Além as HTM e STM, existem outras abordagem mistas de memórias transacionais. A memória transacional hı́brida, do inglês Hybrid Transactional Memory (HyTM), suporta a execução da HTM, mas retorna as transações STM quando os recursos de hardware são excedidos [Kumar et al., 2006]. A STM auxiliada por hardware, do inglês Hardware- assisted STM (HaSTM), combina a STM com um novo suporte da arquitetura para ace- lerar partes da implementação da STM [Shriraman et al., 2006]. Em relação ao desem- penho, a HyTM provém um desempenho próximo a HTM para transações curtas, porém degrada bastante o desempenho quando recorre a STM. Em contrapartida, a HaSTM provém um desempenho mediano entre a HTM e a STM. Para não se estender muito, neste trabalho, focaremos apenas na HyTM. A HyTM combina o esquema otimista e pessimista usando locks de exclusão mútua versionados, no qual suportam sermanticas de exclusão mútua normal e provém acesso a um número de versão que conta o número de vezes o lock foi adquirido e libera- dos. Os projetistas usam exclusão mútua para controle de concorrência pessimistapara dar direito a escrita dos dados protegidos pelos locks e o número de versão permite o contole de concorrência otimista para acessos de leitura. Isto é, uma transação guarda o número da versão antes de sua primeira leitura de um objeto e então, na hora de efetivar- se, verifica se o número da versão mudou, caso não tenha mudado, significa que ninguém atualizou o objeto concorrentemente com a transação. A HyTM também pode ser flexı́vel de acordo com o projeto da STM. Os locks podem suportar buffered updades de duas formas: • Ansiosamente: para prevenir conflitos, embora a transação ainda faça alterações de um log privado. • Preguiçosamente: impedindo as transações de abortarem por causarem conflitos. Os locks também podem suportar gerência de dados. Na STM Bartok, uma transação adquire locks ansiosamente de objetos que ela deseja atualizar, faz as atualizações diretamente no objeto, e gerencia um undo log para permitir que as atualizações sejam revertidas se a transação abortar. Os locks protegem os dados de es- critas conflitantes de transações concorrentes, e faz as atualizações in loco, o que signi- fica as leituras transacionais verão os valores escritos pela mesma transação antecipada- mente. Essa abordagem busca fazer as operações de leituras o mais rápido possı́vel em três hipóteses: • Leituras excederão o número de escritas nas transações; • Lendo número de dados de versões durante uma transação e verificando em tempo de efetivação será mais rápido que adquirir e liberar um lock daquele dado; • Conflitos de transações normalmente serão raros, então é melhor acelerar as transações sem contenção e efetivações, ao custo de um trabalho extra no caso em que os conflitos ocorrem. Em outras palavras “É melhor desculpar-se ocasio- nalmente do que pedir permissão frequentemente” [Herlihy, 1990]. 5. Alguns desafios de projeto Ainda existem outros desafios de projetos de uma TM. Esta seção apresenta rapidamente algumas destes desafios. 5.1. Aninhamento aberta ou fechada É possı́vel embutir as transações dentro de funções de programa, auxiliando o programa- dor a escrever programas eficientes ou utilizar bibliotecas renomadas. Nas transações de aninhamento fechadas, ou todas ou nenhuma das transações em uma região aninhada se efetiva. Em contraste, numa transação de aninhamento aberto, quando uma transação interna efetiva, seu efeito torna-se visı́vel para todos os threads do sistema. O aninhamento aberto permite que as transações liberem mais concorrência que as transações de aninhamento fechado. Quando uma transação de aninhamento aberto se efe- tiva, suas escritas torna-se visı́veis a todas as outras transações, então outras transações po- dem ver modificações mais rapidamente e trabalhar com o dado modificado. Na transação de aninhamento fechado, as modificações são visı́veis apenas quando toda a transação se efetiva. Em contrapartida, transações de aninhamento aberto aumenta a responsabili- dade do programador, que precisa realizar ações que devam compensar quando alguma transação externa é efetivada e quando uma das transações aborta. O desafio aqui é suportar um modelo de aninhamento rico com o mı́nimo de com- plexidade de software-hardware. Uma vez que o mais simples modelo aninhamento fe- chado requer a inclusão de alguma complexidade de hardware enquanto limita a con- corrência e desempenho, os modelos de transações de aninhamento aberto expõem mais concorrência, mas aumenta a complexidade para os programadores, quem deve explicitar as efetivações de escritas e abortos lidando com códigos para suportar esses modelos. A figura 3 ilustra um exemplo de código para transações de aninhamento aberto e fechado: a figura 3a é o código original; a figura 3b é o código de uma transação de aninhamento fechado; a figura 3c é o código de uma transação de aninhamento aberto. 5.2. Entrada e saı́da A relação entre operações de Entrada e Saı́da (E/S) e transações é outra área de pes- quisa desafiadora. Por exemplo, suponha que dentro de uma transação, uma chamada de sistema tenta escrever um caractere no terminal. Uma solução é executar a chamada de sistema imediatamente; contudo, isto pode ser muito problemático se esta transação abortar depois. Tentar desfazer o E/S através da deleção do caractere sobre um aborto pode obviamente levar a um sistema incerto (ou inseguro). Em alguns casos, uma vez executado a operação de E/S deve ser difı́cil se o dado estiver buferizado em HTM. Outra solução é deferir a operação de E/S até a efetivação para colocar o caractere no terminal. Porém, isso pode levar a algum problema se o usuário está aguardando a E/S para realizar alguma ação. Figura 3: Exemplo de código para transações de aninhamento aberto e fechado [Harris et al., 2010]. Uma terceira abordagem é proibir (ou restrigir) operações E/S dentro de transações. Uma quarta solução seria categorizar as entradas e saı́das de acordo com suas propriedades abortivas. O programador deve tomar cuidado com o tipo de operação de E/S que não faz sentido estarem contidos numa simples transação atômica. Por exemplo, durante uma transação, aguardar uma entrada do usuário. 5.3. Modelos de programação e TM Alguns modelos de programação incluem uma declaração atômica para definir os blocos atômicos. Alguns casos, uma variável pode ser atribuı́da como atômica, desta forma, qualquer atualização nela no código é tratado como se a atualização é uma seção curta atômica. Outro modelo de programação já estabelecido, como o OpenMP e MPI, que são usados amplamente para aplicações cientı́ficas paralelizáveis, não foram desenvolvidos com a TM em mente. Explorar como a TM pode tornar a programação paralela com esses modelos atraente é outro desafio. Com o OpenMP, o programador deve inserir diretivas de preprocessamento para expressar as oportunidades para explorar o processamento e distribuir o trabalho entre os threads, sincronizar suas execuções. A maior complexidade em escrever aplicações OpenMP é o uso de regiões crı́ticas (locks), regiões atômicas, e barreiras de sincronização para execução das atividades para- lelas nas threads. A forma mais simples de misturar OpenMP e TM é substitui as regiões crı́ticas e atômicas com o código de regiões transacionais, fazendo as aplicações paralelas mais fáceis de programar, entender, e manter. Além do mais, a TM possivelmente pode prover outras vantagens que o modelo de programação OpenMP. Porém, as implementações TM existentes não permitem que múltiplas threads ro- dem em paralelo no mesmo estado transacional. Usando MPI com TM, programadores podem alcançar a tolerância a falha encapsulando cada diretriz padrão do MPI dentro de uma transação com código de gerência para lidar com abortos ou efetivações. O maior desafio aqui é prover implementações que possam propriamente misturar os modelos pre- venindo abortos em cascata. 6. Conclusão A memória transacional provém um mecanismo natural para escrita de programa parale- los. É uma tendência que os modelos de programação atual sejam projetados para traba- lharem com programas concorrentes para aproveitar o máximo do paralelismo dos chips multicores que já estão presentes nos computadores atuais, assim como a extensão dessa escalabilidade usando nuvens computacionais. Por enquanto, o maior desafio é fazer pro- jetos de hardware e software para que a comunidade de programadores adotarem a TM da forma mais fácil possı́vel. Este trabalho teve como objetivo apresentar uma rápida visão sobre as TM e seus desafios de projetos. Referências Culler, D., Singh, J., and Gupta, A. (1999). Parallel computer architecture: a hard- ware/software approach. Morgan Kaufmann. Felber, P., Fetzer, C., Guerraoui, R., and Harris, T. (2008). Transactions are back—butare they the same? ACM SIGACT News, 39(1):48–58. Fraser, K. (2004). Practical lock-freedom. PhD thesis, PhD thesis, Cambridge University Computer Laboratory, 2003. Also available as Technical Report UCAM-CL-TR-579. Gray, J. (1978). Notes on data base operating systems. Operating Systems, pages 393– 481. Harris, T., Cristal, A., Unsal, O., Ayguade, E., Gagliardi, F., Smith, B., and Valero, M. (2007). Transactional memory: An overview. Micro, IEEE, 27(3):8–29. Harris, T., Larus, J., and Rajwar, R. (2010). Transactional memory. Synthesis Lectures on Computer Architecture, 5(1):1–263. Harris, T., Plesko, M., Shinnar, A., and Tarditi, D. (2006). Optimizing memory transacti- ons. In ACM SIGPLAN Notices, volume 41, pages 14–25. ACM. Herlihy, M. (1990). Apologizing versus asking permission: Optimistic concurrency con- trol for abstract data types. ACM Transactions on Database Systems (TODS), 15(1):96– 124. Herlihy, M. and Moss, J. (1993). Transactional memory: Architectural support for lock- free data structures, volume 21. ACM. Kumar, S., Chu, M., Hughes, C., Kundu, P., and Nguyen, A. (2006). Hybrid transactional memory. In Proceedings of the eleventh ACM SIGPLAN symposium on Principles and practice of parallel programming, pages 209–220. ACM. Larus, J. and Rajwar, R. (2007). Transactional memory. Synthesis Lectures on Computer Architecture, 1(1):1–226. Liskov, B. (1988). Distributed programming in argus. Communications of the ACM, 31(3):300–312. Shavit, N. and Touitou, D. (1995). Software transactional memory. In Proceedings of the fourteenth annual ACM symposium on Principles of distributed computing, pages 204–213. ACM. Shriraman, A., Marathe, V., Dwarkadas, S., Scott, M., Eisenstat, D., Heriot, C., Sche- rer III, W., and Spear, M. (2006). Hardware acceleration of software transactional memory. In ACM SIGPLAN Workshop on Transactional Computing, Ottawa, ON, Canada.
Compartilhar