views:

975

answers:

4

In particular

  1. Create a function to take an array and an index as parameters.
  2. Create a n element array.
  3. Create a n count loop.
  4. Inside the loop on a new thread assign a new instance of the object to the array using the indexer passed in.

I know how to manage the threads etc. I am interested in know if this is thread safe way of doing something.

 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);
    }
}

Thanks

Gary

+17  A: 

MSDN documentation on Arrays says:

Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

This implementation does not provide a synchronized (thread safe) wrapper for an Array; however, .NET Framework classes based on Array provide their own synchronized version of the collection using the SyncRoot property.

Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.

So no, they're not thread safe.

Joren
This does not answer my question. I am not doing any enumeration how can this guy get 13 votes?
Gary
A vote means the answer is helpful. Your checkmark indicates than an answer solves your problem. Given this information, if I were developing a threadable class with Arrays, I believe the first thing I would do is fire up Reflector, open up one of the Framework classes that uses Array in a thread-safe context, and see what they are doing with SyncRoot.
Robert Harvey
This answer is truly unhelpful, inasmuch as the MSDN quote is quite misleading *and* not to the point. Array accesses to reference types are atomic; even enumerating over such an array (while probably unwise) is to that degree thread-safe.
Eamon Nerbonne
The title question is "Are C# arrays thread safe". The first line of my answer explicates the thread safety of static and the lack of safety of instance members. Therefore arrays are not thread safe. Any other operations are not about thread safety of the array but rather about thread safety of whatever the array is stored in.
Joren
+10  A: 

I believe that if each thread only works on a separate part of the array, all will be well. If you're going to share data (i. e. communicate it between threads) then you'll need some sort of memory barrier to avoid memory model issues.

I believe that if you spawn a bunch of threads, each of which populates its own section of the array, then wait for all of those threads to finish using Thread.Join, that that will do enough in terms of barriers for you to be safe. I don't have any supporting documentation for that at the moment, mind you ...

EDIT: Your sample code is safe. At no time are two threads accessing the same element - it's as if they each have separate variables. However, that doesn't tend to be useful on its own. At some point normally the threads will want to share state - one thread will want to read what another has written. Otherwise there's no point in them writing into a shared array instead of into their own private variables. That's the point at which you need to be careful - the coordination between threads.

Jon Skeet
Array elements follow the same rules as regular variables, in that swapping a reference will be atomic but replacing a struct will generally not be. This doesn't take into account the need for a memory barrier, though, to make accesses volatile.As you said, whether it's safe is going to depend precisely on what the coder is doing.
Steven Sudit
@Steven: Yup, that was about my understanding :)
Jon Skeet
@Steven "whether it's safe is going to depend precisely on what the coder is doing." - Isn't that the same as saying "No, it's not safe." ?
Rik
Early Intel processors used exactly this strategy to multi-task (8086) - the lower 640kb was reserved for apps and the OS and the remainder for BIOS. Later, hardware support for virtual address ranges (80286, protected mode) pacified the wild west coding of "let's all hack on one array".If you are going to use this technique, do yourself a favor and make use of System.ArraySegment<T>.
Dave
@Rik: No, it's not the same. Thread safety should almost never be simplified to a "yes" or "no" answer.
Jon Skeet
Sample code added
Gary
In my use case after the array is created I will insert the data into the database, but that is another question.
Gary
+3  A: 

Generally when a collection is said to be 'not threadsafe' that means that concurrent accesses could fail internally (e.g. it not safe to read the first element of List<T> while another thread adds an element at the end of the list: the List<T> might resize the underlying array and the read access might go to the new array before the data was copied into it).

Such errors are impossible with arrays because arrays are fixed-size and have no such 'structure changes'. An array with three elements is no more or less thread-safe than three variables.

The C# specification doesn't say anything about this; but it is clear if you know IL and read the CLI specification - you could get a managed reference (like those used for C# "ref" parameters) to an element inside an array and then do both normal and volatile loads and stores to it. The CLI spec describes the thread-safety guarantees for such loads and stores (e.g. atomicity for elements <=32 bit)

So if I'm unterstanding your question correctly, you want to fill an array using different threads, but will assign to each array element only once? If so, that's perfectly thread-safe.

Daniel
+1  A: 

The example you are providing is very similar to the way that Microsoft's own Parallel extensions to C# 4.0 work.

This for loop:

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

becomes

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

So, yes, your example should be OK. Here's an older blog post about the new parallel support in C#.

Eric