Pergunta

Eu fiz um spinlock muito simples de utilizar as funções bloqueadas no Windows e testado-lo em uma CPU dual-core (dois tópicos que incrementar uma variável);

O programa parece funcionar bem (ele dá o mesmo resultado cada vez, o que não é o caso quando nenhuma sincronização é usado), mas Intel Parallel Inspector , diz que há uma condição de corrida em < em> valor + = j (veja o código abaixo). O aviso desaparece ao usar seções críticas em vez de minha SpinLock.

É a minha implementação de SpinLock correta ou não? É realmente estranho, porque todas as operações usados ??são atômicas e ter as barreiras de memória adequadas e não deve levar a condições de corrida.

class SpinLock
{
   int *lockValue;
   SpinLock(int *value) : lockValue(value) { }

   void Lock() {
      while(InterlockedCompareExchange((volatile LONG*)lockValue, 1, 0) != 0) {
          WaitABit();
      }
   }

   void Unlock() { InterlockedExchange((volatile LONG*)lockValue, 0); }
};

O programa de teste:

static const int THREADS = 2;
HANDLE completedEvents[THREADS];
int value = 0;
int lock = 0; // Global.

DWORD WINAPI TestThread(void *param) {
    HANDLE completed = (HANDLE)param;
    SpinLock testLock(&lock);

    for(int i = 0;i < 1000*20; i++) {
        for(int j = 0;j < 10*10; j++) {
            // Add something to the variable.
            testLock.Lock();
            value += j;
            testLock.Unlock();
        }
    }
    SetEvent(completed);
}

int main() {
   for(int i = 0; i < THREADS; i++) {
        completedEvents[i] = CreateEvent(NULL, true, false, NULL);
   }
   for(int i = 0; i < THREADS; i++) {
        DWORD id;
        CreateThread(NULL, 0, TestThread, completedEvents[i], 0, &id);
   }

   WaitForMultipleObjects(THREADS, completedEvents, true, INFINITE);
   cout<<value;
}
Foi útil?

Solução

Paralelo a documentação do Inspector para raça dados sugere o uso de uma seção crítica ou mutex para corridas de correção no Windows. Não há nada nele que sugere que Parallel Inspector sabe reconhecer qualquer outro mecanismo de bloqueio que você pode inventar.

Ferramentas para análise de novos mecanismos de bloqueio tendem a ser ferramentas estáticas que olhar para cada caminho possível através do código, em paralelo a documentação do Inspector implica que ele executa o código de uma vez.

Se você quiser experimentar com novos mecanismos de bloqueio, a ferramenta mais comum que eu vi usado na literatura acadêmica é o spin verificador de modelos . Há também ESP , o que pode reduzir o espaço de estado, mas eu não faço saber se ele foi aplicada a problemas simultâneos, e também o mobilidade bancada o que daria uma análise, se puder sofá seu problema em pi-cálculo. A Intel Parallel Inspector não parecer qualquer coisa como tão complicado como essas ferramentas, mas sim concebida para verificar comumente ocorrem problemas usando heurística.

Outras dicas

Para outros povos pobres em uma situação semelhante a mim: Intel prevê um conjunto de inclui e bibliotecas para fazer exatamente esse tipo de coisa. Verifique no diretório de instalação Inspector (você verá \ incluem, \ lib32 e \ lib64 no diretório de instalação) para esses materiais. Documentação sobre como usá-los (em junho de 2018, embora a Intel não se importa nada sobre como manter ligações consistente):

https: // software .intel.com / eN-uS / inspector-user-guia-windows-apis-de-custom-sincronização

Existem 3 funções:

void __itt_sync_acquired(void *addr)
void __itt_sync_releasing(void *addr)
void __itt_sync_destroy(void *addr)

Eu tenho certeza que ele deve ser implementado da seguinte forma:

class SpinLock
{
   long lockValue;
   SpinLock(long value) : lockValue(value) { }

   void Lock() {
      while(InterlockedCompareExchange(&lockValue, 1, 0) != 0) {
          WaitABit();
      }
   }

   void Unlock() { InterlockedExchange(&lockValue, 0); }
};
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top