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 / 76931596
Accepted
vengy
vengy
Asked: 2023-08-19 01:52:54 +0800 CST2023-08-19 01:52:54 +0800 CST 2023-08-19 01:52:54 +0800 CST

Melhor maneira de bit atomicamente E um byte em C/C++?

  • 772

Atualmente olhando para operações atômicas em C/C++ usando GCC e descobri que variáveis ​​globais alinhadas naturalmente na memória têm leituras e gravações atômicas.

No entanto, eu estava tentando bitwise AND uma variável global e percebi que se resume a uma sequência de leitura-modificação-gravação que é problemática se houver vários threads operando naquele valor de byte.

Depois de algumas pesquisas, decidi por esses dois exemplos:

Exemplo C - extensão GCC__sync_fetch_and_and

#include <stdio.h>
#include <stdint.h>

uint8_t byteC = 0xFF;

int main() {
    __sync_fetch_and_and(&byteC, 0xF0);
    printf("Value of byteC: 0x%X\n", byteC);
    return 0;
}

Exemplo C++ - C++11 usando atômicofetch_and

#include <iostream>
#include <atomic>

std::atomic<uint8_t> byteCpp(0xFF);

int main() {
    byteCpp.fetch_and(0xF0);
    std::cout << "Value of byteCpp: 0x" << std::hex << static_cast<int>(byteCpp.load()) << std::endl;
    return 0;
}

Seguem outros exemplos, mas parecem menos intuitivos e mais caros computacionalmente.

Usando umpthread_mutex_lock

uint8_t byte = 0xFF;
pthread_mutex_t byte_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_lock(&byte_mutex);
byte &= 0xF0;
pthread_mutex_unlock(&byte_mutex);

Usando um mutexlock_guard

#include <mutex>

uint8_t byte;
std::mutex byte_mutex;

void atomic_and() {
    std::lock_guard<std::mutex> lock(byte_mutex);
    byte &= 0xF0;
}

Usando umcompare_exchange_weak

std::atomic<uint8_t> byte;

void atomic_and() {
    uint8_t old_val, new_val;
    do {
        old_val = byte.load();
        new_val = old_val & 0xF0;
    } while (!byte.compare_exchange_weak(old_val, new_val));
}

Pergunta

Qual é o melhor método atômico para uma sequência de leitura-modificação-gravação em um programa C/C++ multithread?

c++
  • 1 1 respostas
  • 107 Views

1 respostas

  • Voted
  1. Best Answer
    Jan Schultke
    2023-08-19T02:06:44+08:002023-08-19T02:06:44+08:00

    [Eu] descobri que variáveis ​​globais alinhadas naturalmente na memória têm leituras e gravações atômicas.

    Isso não é correto no sentido C/C++, apenas no sentido x86_64. É verdade que quaisquer cargas e armazenamentos alinhados em x86_64 são atômicos, mas isso não é correto para a máquina abstrata. Gravar em um bit não atômico de memória simultaneamente é sempre uma corrida de dados, e os desinfetantes de encadeamento podem detectar o erro, mesmo que a arquitetura teoricamente o torne seguro.

    Além disso, a melhor maneira de fazer byte &= 0xf0atomicamente é muito semelhante em C e C++:

    // C++
    #include <atomic>
    std::atomic_uint8_t byte; // or std::atomic<std::uint8_t>
    // ...
    std::uint8_t old = byte.fetch_and(0xf0); /* optionally specify memory order */
    // or
    std::uint8_t old = std::atomic_fetch_and(&byte, 0xf0);
    
    // C (no compiler extensions/intrinsics needed)
    #include <stdatomic.h>
    atomic_uint8_t byte; // or _Atomic uint8_t
    // ...
    uint8_t old = atomic_fetch_and(&byte, 0xf0); /* optionally atomic_fetch_and_explicit */
    

    Os outros métodos (encadeamentos POSIX, std::mutexloop compare_exchangede repetição) são quase certamente piores do que o modo integrado na forma de fetch_andfunções. Se a arquitetura não fornecer diretamente uma instrução busca-AND atômica, a melhor maneira deve ser escolhida. Não é algo com que você tenha que se preocupar.


    Veja também

    • Por que a atribuição de números inteiros em uma variável naturalmente alinhada é atômica em x86?
    • Quais tipos em um computador de 64 bits são naturalmente atômicos em gnu C e gnu C++? -- o que significa que eles têm leituras atômicas e gravações atômicas

    Obrigado a @PeterCordes por compartilhar esses links.

    • 6

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

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

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +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