0

Here is a class field,

class someClass {
  Int someClassField = nil
  ...

(please, please(!) ignore issues of visibility, this question is concerned wih overall design, not language implementation) If I look online at tutorials, I am told this field is safe to use by multiple threads. When the tutorials say safe, they do not mean that one thread can not interfere with the value visible to another. Such interference may be the intention - the field may be a counter. What the tutorials mean is, when one thread changes this field, the field will not be left in an unsafe state. Take this field,

class someClass {
  List<List> someClassField = new List<Int>()
  ...

As I understand, if the field is a simple list, one thread could leave it in an inconsistent state (i.e. partially disconnected). If another thread uses the list it will fail - in a language like C this would be a disaster. Even reading could fail.

Well then, the class used on the field could be asked to copy out it's state (the copying could be extended to a full defence of immutability, but I'm keeping the discussion simple). If the class copies out it's state, then modifications are done away from the copy on the field, in a new copy modified for return. This new, modified copy can be reassigned to the field. But is that assignment threadsafe - in the sense that the value of the field can not be in an inconsistent state - because the allocation of the reference of the new object to the field is atomic?

I'm ignoring all issues of wether a language engine might reorder, cache etc. See the many posts below (Java especially, it seems),

I'd like to work this question on a smaller scale...

Community
  • 1
  • 1
  • 3
    I don't think this question makes very much sense without reference to a particular language. – Baldrick Jan 10 '14 at 13:36
  • There seems to be agreement - conceptually, yes, but language implementations will have volatility issues or no guarantees of atomicity. Thank you all for attempting to reason about something 'not done'. – Rob Crowther Jan 11 '14 at 17:25
  • This question has been marked as "too broad". I was not aware of this mark. – Rob Crowther Jan 11 '14 at 18:11
  • I tagged with several languages - is that the reason, that it is not specific? Had I asked about the details of a design pattern, e.g. Visitor, (also cross-language), would this question have been marked then? I'm very specific about the action under consideration. I guess I failed in saying 'ignore issues of visibility'. Ah well, the information gathered is good, and I believe there is an important point here. – Rob Crowther Jan 11 '14 at 18:38
  • Anyone interested in this question (or it's background) may like to look at, – Rob Crowther Jul 06 '14 at 06:18
  • Update: Anyone looking at this and interested may like to look at the slow-to-emerge-perhaps-due-to-slow-insert-or-limited-applicability Scala [TrieMap academic paper](http://lampwww.epfl.ch/~prokopec/ctries-snapshot.pdf) "We describe a complete lock-free concurrent hash trie data structure implementation for a shared-memory system based on single-word compare-and-swap instructions.". I only conceived, others do... – Rob Crowther Jul 06 '14 at 06:51
  • Further update: This StackOverflow question [multi-threading with immutability](http://stackoverflow.com/questions/17123703/multi-threading-in-scala-dealing-only-with-immutibility/17124316#17124316) has comments about Scala TrieMap usage. – Rob Crowther Jul 06 '14 at 06:53

4 Answers4

1

In most languages object assignment is atomic.

In this specific case you need to be careful though as doing x=new X() there is no guarantee in all languages that X is fully initialized before the assignment. I'm not sure where C# stands on that.

You also have to consider visibility as well as atomicity. In Java for example you would need to make the variable volatile as otherwise changes made in one thread may not be visible in another thread at all.

Tim B
  • 40,716
  • 16
  • 83
  • 128
1

C++ defines a data race as two or more threads potentially accessing the same memory location simultaneously, at least one of which is a modification. The behavior of programs with data races is undefined. So no, it is not safe for multiple threads to access this field if at least one of them may modify it.

Casey
  • 41,449
  • 7
  • 95
  • 125
1

In Java the assignment to references and primitives are atomic except for the 64bit primitive types long and double. Assignments to Java longs and doubles can be made atomic by declaring them with the volatile modifier. See: Are 64 bit assignments in Java atomic on a 32 bit machine?

This is so because the Java VM specification requires it in order for the VM to be Java compliant.

Scala runs on top of a standard Java VM and so will also provide the same guarantees as Java with respect to assignments unless they start using JNI.

One of the problems with C/C++ (and one of its strengths) is that both languages allow very fine grained mapping of data structures to memory addresses. At this level, whether writes to memory are atomic or not depend very much on the hardware platform. For instance, CPU's are usually unable to atomically read, let alone write to variables that are not aligned appropriately. e.g. When 16bit variables aren't aligned to even addresses, or when 32bit variables aren't aligned to addresses that are a multiple of 4, and so on. It gets worse when the variable extends beyond one cache line into the next, or beyond one page into the next. Hence C does not guarantee that assignments will be atomic.

Community
  • 1
  • 1
Nam San
  • 1,145
  • 9
  • 13
1

Writing a reference in Java is atomic (writes to longs or doubles are only if the field is volatile btw), but that alone doesn't help you at all.

Example to demonstrate:

class Foo {
     int x;
     public Foo() { x = 5};
}

Now assume we do an assignment such as foo = new Foo() (without final or volatile modifiers for foo!). From a low level point of view that means we have to do the following:

  1. allocate memory
  2. run the constructor
  3. assign memory address to the field.

but as long as the constructor doesn't read the field we're assigning it to, the compiler can just as well do the following:

  1. allocate memory
  2. assign memory address to the field.
  3. run the constructor

Thread-safe? Certainly not (and you're never guaranteed to actually see the update if you don't put memory barriers in). Java gives more guarantees when final fields are involved, so creating a new immutable object will be thread-safe (you'll never see the uninitialized value of a final field). Volatile fields (we're talking about the assignment here not fields in the object) avoid this problem too in both java and c#. Not sure about C# and readonly though.

Voo
  • 29,040
  • 11
  • 82
  • 156