Según mi entendimiento, dada una matriz C #, el acto de iterar sobre la matriz simultáneamente desde múltiples subprocesos es una operación segura para subprocesos.
Al iterar sobre la matriz, me refiero a leer todas las posiciones dentro de la matriz mediante un bucle antiguo simplefor
. Cada subproceso simplemente lee el contenido de una ubicación de memoria dentro de la matriz, nadie escribe nada, por lo que todos los subprocesos leen lo mismo de manera coherente.
Este es un fragmento de código que hace lo que escribí anteriormente:
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;
}
}
Entonces, entiendo que el método DoSomethingUseless
es seguro para subprocesos y que no hay necesidad de reemplazarlo string[]
con un tipo seguro para subprocesos (como, ImmutableArray<string>
por ejemplo).
Estoy en lo correcto ?
Ahora supongamos que tenemos una instancia de IEnumerable<T>
. No sabemos cuál es el objeto subyacente, solo sabemos que tenemos un objeto implementado IEnumerable<T>
, por lo que podemos iterar sobre él utilizando el foreach
bucle.
Según mi entendimiento, en este escenario no hay garantía de que iterar sobre este objeto desde varios subprocesos al mismo tiempo sea una operación segura para subprocesos. Dicho de otra manera, es completamente posible que iterar sobre la IEnumerable<T>
instancia desde diferentes hilos al mismo tiempo rompa el estado interno del objeto, de modo que se corrompa.
¿Estoy en lo cierto en este punto?
¿Qué pasa con la IEnumerable<T>
implementación de la Array
clase? ¿Es seguro para hilos?
Dicho de otra manera, ¿es seguro el siguiente hilo de código? (este es exactamente el mismo código que el anterior, pero ahora la matriz se repite utilizando un foreach
bucle en lugar de un for
bucle)
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;
}
}
¿Hay alguna referencia que indique qué IEnumerable<T>
implementaciones en la biblioteca de clase base .NET son realmente seguras para subprocesos?
Array
) será seguro para subprocesos siempre que todos los subprocesos solo lo lean. Lo mismo con List<T>
, y probablemente con cualquier otra colección escrita por Microsoft. Pero es posible hacer uno propio IEnumerable
que haga cosas que no sean seguras para subprocesos en el enumerador. Por lo tanto, no es una garantía de que todo lo que implemente IEnumerable
sea seguro para subprocesos.
foreach
funciona con más que solo enumeradores. El compilador es lo suficientemente inteligente como para saber que si tiene información de tipo estático que indica que la colección es una matriz, omite generar el enumerador y solo accede a la matriz directamente como si fuera un for
bucle. Del mismo modo, si la colección admite una implementación personalizada de GetEnumerator
, esa implementación se usa en lugar de llamar IEnumerable.GetEnumerator
. La noción de que foreach
solo se trafica IEnumerable/IEnumerator
es falsa.
volatile
no garantiza que obtenga la actualización más reciente posible a una variable porque C # permite que diferentes hilos observen diferentes ordenamientos de lecturas y escrituras, y por lo tanto la noción de "más reciente" no está definida globalmente . En lugar de razonar sobre la frescura, razone sobre las restricciones que volatile
impone la forma en que se pueden reordenar las escrituras.