Existem inúmeras perguntas aqui. Considerando-os um de cada vez:
a atribuição de referência é atômica, então por que Interlocked.Exchange (ref Object, Object) é necessário?
A atribuição de referência é atômica. Interlocked.Exchange não faz apenas referência à atribuição. Ele faz uma leitura do valor atual de uma variável, armazena o valor antigo e atribui o novo valor à variável, tudo como uma operação atômica.
meu colega disse que em algumas plataformas não é garantido que a atribuição de referência seja atômica. Meu colega estava correto?
Não. A atribuição de referência tem garantia de ser atômica em todas as plataformas .NET.
Meu colega está raciocinando com base em premissas falsas. Isso significa que suas conclusões estão incorretas?
Não necessariamente. Seu colega pode estar lhe dando bons conselhos por motivos ruins. Talvez haja algum outro motivo pelo qual você deva usar o Interlocked.Exchange. Programar sem travas é extremamente difícil e no momento em que você se afasta das práticas bem estabelecidas adotadas por especialistas na área, você está perdido e se arriscando nas piores condições de corrida. Não sou um especialista neste campo nem um especialista em seu código, portanto, não posso fazer um julgamento de uma forma ou de outra.
produz um aviso "uma referência a um campo volátil não será tratada como volátil" O que devo pensar sobre isso?
Você deve entender porque isso é um problema em geral. Isso levará a uma compreensão de por que o aviso não é importante neste caso específico.
O motivo pelo qual o compilador dá este aviso é porque marcar um campo como volátil significa "este campo será atualizado em vários segmentos - não gere nenhum código que armazene em cache os valores deste campo e certifique-se de que qualquer leitura ou gravação de este campo não é "movido para frente e para trás no tempo" por meio de inconsistências do cache do processador. "
(Presumo que você já entenda tudo isso. Se você não tem uma compreensão detalhada do significado de volátil e como ele afeta a semântica do cache do processador, então você não entende como funciona e não deveria usar volátil. Programas sem bloqueio são muito difíceis de acertar; certifique-se de que seu programa está certo, porque você entende como ele funciona, não acertadamente por acidente.)
Agora suponha que você crie uma variável que é um apelido de um campo volátil, passando um ref para esse campo. Dentro do método chamado, o compilador não tem nenhuma razão para saber que a referência precisa ter semântica volátil! O compilador gerará alegremente o código para o método que falha em implementar as regras para campos voláteis, mas a variável é um campo volátil. Isso pode destruir completamente sua lógica sem bloqueio; a suposição é sempre que um campo volátil é sempre acessado com semântica volátil. Não faz sentido tratá-lo como volátil algumas vezes e não outras; você tem que ser sempre consistente, caso contrário não pode garantir consistência em outros acessos.
Portanto, o compilador avisa quando você faz isso, porque provavelmente vai bagunçar completamente sua lógica livre de bloqueio cuidadosamente desenvolvida.
Claro, Interlocked.Exchange foi escrito para esperar um campo volátil e fazer a coisa certa. O aviso é, portanto, enganoso. Lamento muito isso; o que deveríamos ter feito é implementar algum mecanismo pelo qual um autor de um método como Interlocked.Exchange poderia colocar um atributo no método dizendo "este método que recebe uma referência impõe semântica volátil na variável, então suprima o aviso". Talvez em uma versão futura do compilador façamos isso.