Como clonar um disco rígido
Na era digital moderna, onde os dados são um bem valioso, a clonagem de um disco rígido no Windows pode ser um processo crucial para muitos. Este guia completo
Historicamente, todos os programas de computador foram escritos de forma totalmente sequencial. Isso é simples de ler, escrever e entender. Também é simples para um computador executar e requer um hardware relativamente simples. Com esse paradigma de design, as duas únicas maneiras de aumentar o desempenho do sistema são escrever um código mais eficiente e aumentar a velocidade da CPU. Aumentar a eficiência do código pode ser possível, mas geralmente é um processo complexo com resultados geralmente limitados.
Durante décadas, o desempenho poderia ser reduzido esperando por CPUs novas e mais eficientes. Conforme descrito pela lei de Moore, as CPUs quase dobram de desempenho a cada dois ou três anos. Infelizmente, a maioria desses ganhos de desempenho veio do uso de nós de fabricação cada vez menores. A tecnologia moderna tem lutado para diminuir o tamanho do nó na taxa histórica, graças a dificuldades materiais trabalhando na escala de nanômetros.
Para contornar isso, os arquitetos de CPU modernos optaram por adicionar vários núcleos de processador às CPUs. Cada núcleo do processador pode atuar de forma independente em uma tarefa diferente. Embora não possam combinar o mesmo problema, podem trabalhar em duas questões simultaneamente. Essa mudança arquitetônica fundamental fornece muito desempenho extra, mas não beneficia diretamente os processos individuais, embora reduza a contenção do tempo do processador.
Para aproveitar as vantagens das CPUs com vários núcleos, o código deve ser escrito de maneira multiencadeada. Cada encadeamento pode ser executado simultaneamente, dimensionando o benefício de desempenho pelo número de encadeamentos e núcleos de CPU disponíveis. Fazer isso, porém, esbarra em um novo desafio, a “condição de corrida”.
Observação: algumas tarefas não podem ser multiencadeadas, enquanto outras podem ser massivamente multiencadeadas. Os possíveis benefícios de desempenho dependem do trabalho que está sendo feito.
Condições da corrida
O software multiencadeado pode tirar proveito de vários núcleos. Os perigos estão à espreita nessas águas, prontos para prender o programador inexperiente. Uma condição de corrida pode ocorrer quando dois threads diferentes interagem com o mesmo bit de memória.
Um exemplo simples poderia ser dois threads tentando verificar e incrementar uma variável simultaneamente. Digamos que a=0 . Dois threads diferentes executam suas funções e, em algum momento, verificam a e incrementam-no em um. Geralmente, você esperaria que o resultado de dois threads adicionando um a zero fosse dois. Na maioria das vezes, este deve ser o caso. Você pode obter um resultado diferente se ambos os encadeamentos passarem por essa funcionalidade específica precisamente no momento certo.
Nesse caso, o primeiro thread lê o valor de a . Antes que o primeiro thread possa incrementar o valor de um pensamento, o segundo thread o lê. Agora a primeira thread soma um a zero, mas a segunda thread já acredita que o valor seja zero, somando um a zero. O resultado disso é que o valor final de a é 1, não 2.
Corrida para o pior cenário
Embora o exemplo acima possa não parecer particularmente ruim, ele pode ter efeitos dramáticos. E se o valor de a selecionar o modo de operação de uma máquina? E se modos específicos de operação dessa máquina puderem ser perigosos ou até mesmo fatais?
As condições da corrida também não precisam ser tão simples. Por exemplo, pode ser possível que um thread leia uma seção de memória ao mesmo tempo em que outro thread está gravando nela. Nesse caso, o thread de leitura pode obter uma mistura estranha dos dados de antes e depois. Digamos que a verificação seja uma verificação simples de verdadeiro/falso.
Se a variável disse true no início da leitura, mas estava no processo de ser substituída pela palavra false, o resultado da operação de leitura pode ser algo como “trlse”. Isso não é "verdadeiro" ou "falso". Não ser nenhuma das duas opções em uma escolha binária quase certamente resultaria na falha do aplicativo. Essa corrupção de memória pode levar a muitos problemas de segurança, como negação de serviço e escalonamento de privilégios.
Bloqueando a Corrida
Saber quais bits de memória em um programa são compartilhados entre diferentes threads é essencial para evitar uma condição de corrida. Nada precisa ser feito se uma variável só for controlada e acessível por um único thread. Se dois ou mais threads puderem acessar uma variável, você deve garantir que todas as operações nessa parte da memória sejam concluídas independentemente umas das outras.
Esta independência é conseguida graças a uma fechadura. No código de um programa, você precisa colocar um bloqueio ao escrever uma função que opera em um pedaço de memória compartilhado. Esse bloqueio impede que outros threads acessem esse pedaço de memória até que o bloqueio seja liberado.
A fechadura não é a solução mais elegante. Por um lado, tem sobrecargas de memória. Ele também pode forçar um encadeamento a travar, esperando que um bloqueio seja liberado. Dependendo da situação, o bloqueio pode não ser liberado por muito tempo ou pode não ser liberado. Na pior das hipóteses, desbloquear um bloqueio pode depender de algo acontecendo em outro encadeamento bloqueado, levando a um impasse.
É essencial otimizar o uso de fechaduras. Você pode controlar a granularidade do bloqueio. Por exemplo, se estiver editando dados em uma tabela, você pode bloquear a tabela inteira ou apenas a linha editada. Bloquear a tabela inteira seria um bloqueio de granularidade grosseira. Ele minimiza a sobrecarga da implementação de muitos bloqueios, mas aumenta a chance de que outro thread seja bloqueado pelo bloqueio. Bloquear apenas a linha seria um bloqueio de granularidade fino. É muito menos provável que isso interfira com outros encadeamentos, mas significa que serão necessários bloqueios quebrados, aumentando a sobrecarga total.
Conclusão
Um bloqueio de memória é uma ferramenta de código usada para garantir a atomicidade das operações na memória em um ambiente multiencadeado. Ao bloquear um pedaço de memória antes de operar nele, você pode ter certeza de que nenhum comportamento inesperado pode ocorrer devido a uma condição de corrida. Os bloqueios de memória vêm com uma sobrecarga de memória, mas também podem causar bloqueio.
O bloqueio é onde outro thread tenta operar em uma memória bloqueada. O fio fica lá, bloqueado até que a trava seja liberada. Isso pode causar problemas se a liberação do bloqueio exigir que outro encadeamento faça algo, pois ele pode ser bloqueado antes de concluir o pré-requisito para liberar o bloqueio que o bloqueia. Os bloqueios de memória podem ser evitados escrevendo códigos sem bloqueio. Fazer isso, no entanto, pode ser complexo e menos eficaz do que utilizar bloqueios. Não se esqueça de deixar seus comentários abaixo.
Na era digital moderna, onde os dados são um bem valioso, a clonagem de um disco rígido no Windows pode ser um processo crucial para muitos. Este guia completo
Você está enfrentando a mensagem de erro ao inicializar o computador, informando que o driver WUDFRd falhou ao carregar no seu computador?
Você está enfrentando o código de erro 0x0003 da experiência NVIDIA GeForce em sua área de trabalho? Se sim, leia o blog para descobrir como corrigir esse erro de forma rápida e fácil.
Aprendendo sobre impressão 3D? Aqui está o que você precisa saber sobre a adesão da base da impressora.
Você precisa remover a GPU do seu PC? Junte-se a mim enquanto explico como remover uma GPU do seu PC neste guia passo a passo.
Comprou um novo SSD NVMe M.2, mas não sabe como instalar? Continue lendo para saber como instalar um SSD NVMe em um laptop ou desktop.
Uma bomba lógica é um incidente de segurança em que um invasor configura uma ação atrasada. Continue lendo para saber mais.
O Stuxnet era um worm autopropagado. Foi o primeiro uso de uma arma cibernética e a primeira ocorrência de malware.
Um hacker ético é um hacker que age dentro das restrições da lei. Continue lendo para saber mais sobre o assunto.
Existem muitas partes diferentes da criptografia. Se você deseja criptografar alguns dados, existem dois tipos de algoritmos que você pode usar: simétrico