AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79582320
Accepted
Enlico
Enlico
Asked: 2025-04-19 19:25:32 +0800 CST2025-04-19 19:25:32 +0800 CST 2025-04-19 19:25:32 +0800 CST

Por que o primeiro argumento do colchete deve executar no máximo uma operação de bloqueio?

  • 772

Em Programação Paralela e Concorrente em Haskell de Simon Marlow, a implementação de bracketé mostrada,

bracket
        :: IO a         -- ^ computation to run first (\"acquire resource\")
        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
        -> (a -> IO c)  -- ^ computation to run in-between
        -> IO c         -- returns the value from the in-between computation
bracket before after thing =
  mask $ \restore -> do
    a <- before
    r <- restore (thing a) `onException` after a
    _ <- after a
    return r

e um comentário segue. Aqui está a parte que está me intrigando

[…] É normal que beforecontenha uma operação de bloqueio; se uma exceção for gerada enquanto beforeestiver bloqueado, não haverá danos. Mas beforedeve executar apenas uma operação de bloqueio. Uma exceção gerada por uma segunda operação de bloqueio não resultaria em afterexecução. […]

Não entendi bem esse comentário, então gostaria de alguns esclarecimentos sobre ele.

Para esclarecer, não entendi nem a parte de que nenhum dano é causado : algumas páginas antes (p. 159), a seguinte tentativa falhada (segunda) de chamar takeMVar, executar uma operação dependendo de seu conteúdo e, finalmente, colocar o resultado dessa operação de volta na MVarvia putMVaré mostrada,

problem :: MVar a -> (a -> IO a) -> IO ()
problem m f = mask $ \restore -> do
  a <- takeMVar m
  r <- restore (f a) `catch`  \e -> do putMVar m a; throw e
  putMVar m r

Ao analisar este exemplo, "aceito" como um fato que takeMVarnão pode ser alterado maté que retorne; na verdade, isso foi retirado do texto:

seria seguro que exceções fossem levantadas até o ponto em que takeMVarretornasse.

e sinto que entendo o que se segue (eu acho ).

Mas voltando à implementação de bracket, e se beforeinternamente usar takeMVar, e uma exceção assíncrona ocorrer após o takeMVarretorno dela (esvaziando um MVar)? Isso não é um problema, justamente pelo motivo de estarmos usando mask+ restore, ou seja, tal exceção seria adiada até que o argumento para restore, que é thing a, comece a ser executado, momento em que o manipulador de exceções necessário está em vigor, neste caso via `onException` after a?

E o que dá errado se beforefizer outra chamada para a operação de bloqueio, digamos takeMVarnovamente para simplificar? O problema ocorre porque a exceção poderia ocorrer enquanto takeMVar o bloqueio estiver em andamento, portanto, na janela de tempo em que as exceções não são mascaradas, de modo que a exceção sairia de bracket, deixando o MVarargumento that was para o primeiro takeMVarnão vazio, mas em um estado diferente do original, dado que afternão teve a chance de ser executado?

É isso?

Além disso, a página do documento não menciona isso, ou não vejo como isso está implícito.

exception
  • 1 1 respostas
  • 91 Views

1 respostas

  • Voted
  1. Best Answer
    danidiaz
    2025-04-19T21:34:13+08:002025-04-19T21:34:13+08:00

    Imagine que, no argumento before para bracket, você tentou abrir dois arquivos diferentes, um depois do outro. (E também, correspondentemente, que você tentou fechá-los no argumento after ).

    Se a tentativa de abrir o primeiro arquivo falhar por qualquer motivo, nenhum identificador será alocado e não haverá nada para limpar.

    Mas suponha que o primeiro arquivo seja aberto com sucesso, mas a tentativa de abrir o segundo arquivo falhe (talvez por si só, talvez por alguma exceção assíncrona recebida durante o bloqueio). Como after não é chamado para exceções geradas durante before , o identificador do primeiro arquivo permanecerá aberto.

    E se antes usarmos internamente takeMVar e uma exceção assíncrona ocorrer após o retorno desse takeMVar (esvaziando um MVar)? Isso não é um problema, justamente pelo fato de estarmos usando mask+restore, ou seja, tal exceção seria adiada até que o argumento para restore, que é a coisa a, comece a ser executado, momento em que o manipulador de exceções necessário estará em vigor, neste caso via onExceptionafter a?

    Isso está correto. Quando estamos em um estado "mascarado", exceções assíncronas só podem ocorrer quando uma operação interrompível (como takeMVar) é bloqueada.

    Como menciona o capítulo "Mascarando exceções assíncronas" do livro:

    Pense na máscara como uma "mudança para o modo de pesquisa" para exceções assíncronas. Dentro de uma máscara, exceções assíncronas não são mais assíncronas, mas ainda podem ser geradas por determinadas operações. Em outras palavras, exceções assíncronas se tornam síncronas dentro da máscara.

    • 3

relate perguntas

  • Comportamento inesperado de `with-handlers` em Racket digitado

  • Por que torch.cuda.OutOfMemoryError não é uma classe de erro válida?

  • Como interpretar a referência de memória no lado direito da equação de montagem?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve