Pergunta

Na maioria das plataformas comuns (sendo mais importante o x86, eu entendo que algumas plataformas têm modelos de memória extremamente difíceis que fornecem quase não garante útil para multithreading, mas eu não me importo com contra-exemplos raros), é o seguinte código seguro?

Thread 1:

someVariable = doStuff();
atomicSet(stuffDoneFlag, 1);

Thread 2:

while(!atomicRead(stuffDoneFlag)) {}  // Wait for stuffDoneFlag to be set.
doMoreStuff(someVariable);

padrão Assumindo, implementações razoáveis ??de ops atômicas:

  1. É atribuição da linha 1 do para someVariable garantido para concluir antes atomicSet() é chamado?
  2. É Thread 2 garantido para ver a atribuição para someVariable antes de chamar doMoreStuff() desde que lê stuffDoneFlag atomicamente?

Edições:

  1. A implementação de ops atômicas que estou usando contém as instruções x86 LOCK em cada operação, se isso ajuda.
  2. Suponha stuffDoneFlag está devidamente limpo de alguma forma. Como não é importante.
  3. Este é um exemplo muito simplificado. Eu criei-lo desta forma, para que você não teria que entender todo o contexto do problema para respondê-la. Eu sei que não é eficiente.
Foi útil?

Solução

Se o seu código x86 real tem a loja para someVariable antes que a loja em atomicSet em Thread 1 e carga de someVariable após a carga em atomicRead em Thread 2, então você deve ser fino. Manual de Software da Intel do desenvolvedor 3A Volume especifica o modelo de memória para x86 na Seção 8.2, e os intra-thread store-de armazenamento e carregamento de carga restrições deve ser suficiente aqui.

No entanto, pode não haver nada impedindo o seu compilador de reordenar as instruções geradas a partir de qualquer linguagem de alto nível que você está usando através das operações atômicas.

Outras dicas

1) Sim

2) Sim

Tanto o trabalho.

Este código é thread-safe, mas eu questiono a eficiência de seu spinlock (o tempo circular) a menos que você está apenas girando por um período muito curto de tempo. Não há nenhuma garantia em qualquer sistema que Thread 2 não vai monopolizar completamente todos os tempos de processamento.

Eu recomendaria usar algumas primitivas de sincronização reais (parece boost :: condition_variable é o que você quer aqui) em vez de contar com o bloqueio de rotação.

As instruções atômicas garantir que os fios 2 aguarda o thread 1 para completar a definição da variável antes de rosca 2 prossegue. Há, no entanto, duas questões-chave:

1) a someVariable deve ser declarada ' volátil' para garantir que o compilador não otimizar a sua alocação por exemplo, armazená-lo num registo ou adiamento de uma escrita.

2) da segunda rosca está a bloquear, enquanto espera para o sinal (denominado spinlocking ). Sua plataforma provavelmente fornece muito melhor bloqueio e sinalização primatives e mecanismos, mas uma melhoria relativamente simples seria a de simplesmente sleep() no corpo while() o fio 2 do.

dsimcha escrito: "Suponha stuffDoneFlag está devidamente limpo de alguma forma Como não é importante.". Isso não é verdade!

Vamos cenário ver:

  1. cheques Thread2 o stuffDoneFlag se é um começo lendo someVariable.
  2. Antes do acabamento Thread2 lendo o agendador de tarefas de interrupção da sua missão e suspender a tarefa por algum tempo.
  3. Thread1 novamente acesso ao someVariable e mudar o conteúdo da memória.
  4. interruptor Task Scheduler novamente Thread2 e continuar o trabalho, mas o conteúdo da memória de someVariable é alterado!
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top