Com base no meu entendimento, dado um array C #, o ato de iterar sobre o array simultaneamente de vários threads é uma operação segura para threads.
Ao iterar sobre a matriz, quero dizer a leitura de todas as posições dentro da matriz por meio de um loop antigo simplesfor
. Cada thread está simplesmente lendo o conteúdo de um local de memória dentro da matriz, ninguém está escrevendo nada, então todos os threads lêem a mesma coisa de maneira consistente.
Este é um pedaço de código fazendo o que escrevi acima:
public class UselessService
{
private static readonly string[] Names = new [] { "bob", "alice" };
public List<int> DoSomethingUseless()
{
var temp = new List<int>();
for (int i = 0; i < Names.Length; i++)
{
temp.Add(Names[i].Length * 2);
}
return temp;
}
}
Portanto, meu entendimento é de que o método DoSomethingUseless
é seguro para threads e que não há necessidade de substituí-lo string[]
por um tipo seguro de thread (como ImmutableArray<string>
por exemplo).
Estou correcto ?
Agora vamos supor que temos uma instância de IEnumerable<T>
. Não sabemos qual é o objeto subjacente, apenas sabemos que temos um objeto implementado IEnumerable<T>
, portanto, podemos iterá-lo usando o foreach
loop.
Com base no meu entendimento, nesse cenário, não há garantia de que a iteração desse objeto a partir de vários threads simultaneamente seja uma operação segura de thread. Em outras palavras, é perfeitamente possível que a iteração sobre a IEnumerable<T>
instância de diferentes threads ao mesmo tempo quebre o estado interno do objeto, para que ele seja corrompido.
Estou correto neste ponto?
E a IEnumerable<T>
implementação da Array
classe? É thread seguro?
Em outras palavras, o seguinte encadeamento de código é seguro? (esse é exatamente o mesmo código acima, mas agora a matriz é iterada usando um foreach
loop em vez de um for
loop)
public class UselessService
{
private static readonly string[] Names = new [] { "bob", "alice" };
public List<int> DoSomethingUseless()
{
var temp = new List<int>();
foreach (var name in Names)
{
temp.Add(name.Length * 2);
}
return temp;
}
}
Existe alguma referência informando que IEnumerable<T>
implementações na biblioteca de classes base do .NET são realmente seguras contra threads?
Array
) será segura para threads, desde que todas as threads estejam apenas lendo. O mesmo com List<T>
e provavelmente todas as outras coleções escritas pela Microsoft. Mas é possível criar o seu próprio IEnumerable
que faz coisas seguras sem thread no enumerador. Portanto, não é uma garantia de que tudo o que implementa IEnumerable
seja seguro para threads.
foreach
funciona com mais do que apenas enumeradores. O compilador é inteligente o suficiente para saber que, se tiver informações de tipo estático indicando que a coleção é uma matriz, ele pula a geração do enumerador e acessa a matriz diretamente como se fosse um for
loop. Da mesma forma, se a coleção suportar uma implementação personalizada de GetEnumerator
, essa implementação será usada em vez de chamar IEnumerable.GetEnumerator
. A noção em que foreach
apenas trafega IEnumerable/IEnumerator
é falsa.
volatile
não garante que você obtenha a atualização mais recente possível para uma variável porque o C # permite que diferentes segmentos observem diferentes ordenações de leituras e gravações e, portanto, a noção de "mais recente" não é definida globalmente . Em vez de raciocinar sobre atualização, raciocine sobre quais restrições volatile
colocam a forma como as gravações podem ser reordenadas.