Os arrays de matrizes C # são seguros?

Em particular

  1. Crie uma function para obter uma matriz e um índice como parâmetros.
  2. Crie uma matriz de elementos.
  3. Crie um loop de contagem.
  4. Dentro do loop em um novo thread, atribua uma nova instância do object ao array usando o indexador passado.

Eu sei como gerenciar os tópicos etc. Estou interessado em saber se esta é uma maneira segura de fazer algo.

class Program { // bogus object class SomeObject { private int value1; private int value2; public SomeObject(int value1, int value2) { this.value1 = value1; this.value2 = value2; } } static void Main(string[] args) { var s = new SomeObject[10]; var threads = Environment.ProcessorCount - 1; var stp = new SmartThreadPool(1000, threads, threads); for (var i = 0; i < 10; i++) { stp.QueueWorkItem(CreateElement, s, i); } } static void CreateElement(SomeObject[] s, int index) { s[index] = new SomeObject(index, 2); } } 

Eu acredito que se cada thread só funciona em uma parte separada da matriz, tudo ficará bem. Se você for compartilhar dados (ou seja, comunicá-los entre threads), precisará de algum tipo de barreira de memory para evitar problemas no modelo de memory.

Eu acredito que se você gerar um monte de threads, cada um dos quais preenche sua própria seção da matriz, então espere que todos esses threads terminem usando Thread.Join , que isso fará o suficiente em termos de barreiras para você estar seguro . Eu não tenho nenhuma documentação de apoio para isso no momento, lembre-se …

EDIT: Seu código de exemplo é seguro. Em nenhum momento duas linhas acessam o mesmo elemento – é como se cada uma tivesse variables ​​separadas. No entanto, isso não costuma ser útil por si só. Em algum momento, normalmente, os threads vão querer compartilhar o estado – um thread vai querer ler o que outro escreveu. Caso contrário, não há sentido em escrever em um array compartilhado em vez de em suas próprias variables ​​privadas. Esse é o ponto em que você precisa ter cuidado – a coordenação entre os tópicos.

A documentação do MSDN sobre matrizes diz:

Público static (Shared no Visual Basic) membros deste tipo são thread-safe. Não é garantido que qualquer membro da instância seja thread-safe.

Essa implementação não fornece um wrapper sincronizado (thread safe) para uma matriz; no entanto, as classs do .NET Framework baseadas no Array fornecem sua própria versão sincronizada da coleção usando a propriedade SyncRoot.

Enumerar através de uma coleção é intrinsecamente não um procedimento thread-safe. Mesmo quando uma coleção é sincronizada, outros segmentos ainda podem modificar a coleção, o que faz com que o enumerador lance uma exceção. Para garantir a segurança do encadeamento durante a enumeração, você pode bloquear a coleção durante toda a enumeração ou capturar as exceções resultantes de alterações feitas por outros encadeamentos.

Então, não, eles não são seguros.

Geralmente, quando uma coleção é ‘não threadsafe’, significa que os accesss simultâneos podem falhar internamente (por exemplo, não é seguro ler o primeiro elemento de List enquanto outro thread adiciona um elemento no final da lista: pode resize a matriz subjacente e o access de leitura pode ir para a nova matriz antes que os dados sejam copiados para ela).

Tais erros são impossíveis em matrizes porque os arrays são de tamanho fixo e não têm tais ‘mudanças de estrutura’. Um array com três elementos não é mais ou menos thread-safe do que três variables.

A especificação do C # não diz nada sobre isso; mas fica claro se você conhece IL e lê a especificação CLI – você poderia obter uma referência gerenciada (como aquelas usadas para os parâmetros “ref” do C #) para um elemento dentro de uma matriz e então fazer carregamentos e armazenamentos normais e voláteis. A especificação CLI descreve as garantias de segurança de rosca para tais cargas e armazenamentos (por exemplo, atomicidade para elementos < = 32 bits)

Então, se eu estou entendendo sua pergunta corretamente, você quer preencher uma matriz usando diferentes threads, mas irá atribuir a cada elemento da matriz apenas uma vez? Se assim for, isso é perfeitamente thread-safe.

O exemplo que você está fornecendo é muito semelhante ao modo como as extensões Parallel da Microsoft para o C # 4.0 funcionam.

Este loop for:

 for (int i = 0; i < 100; i++) { a[i] = a[i]*a[i]; } 

torna-se

 Parallel.For(0, 100, delegate(int i) { a[i] = a[i]*a[i]; }); 

Então, sim, seu exemplo deve ser OK. Aqui está uma postagem de blog mais antiga sobre o novo suporte paralelo em C #.