5

I am currently reading Joe Albahari's Threading in C# e-book, and sometimes in his example code, he uses locks in places where I don't see any thread safety issue. Here, for example, he locks around writing to and reading from the _status field, which refers to an immutable object.

I understand that if the ProgressStatus class were mutable, you would need to lock around reading from and writing to it, because if one thread were pre-empted in between updating the PercentComplete and StatusMessage fields by another thread reading the status, the second thread might get an invalid pair of values for those fields. (100% complete / "Operation in progress...")

But since ProgressStatus is immutable, no such invalid status can occur. If Joe removed both of those locks, what thread safety issue could arise?

dgmulf
  • 475
  • 1
  • 3
  • 5

2 Answers2

4

Readers might never see _status update to a new value, for example. All reads might be collapsed into one physical read.

Also, I think you might see partially initialized objects in case _status was committed to memory before the fields in the object being referenced.

Note, that this locking has nothing to do with the object being referenced. This is about protecting the reference itself.

Accessing a variable on multiple threads when one of the accesses is a write is a data race. All kinds of things can happen. What I said above are just examples.

usr
  • 168,620
  • 35
  • 240
  • 369
  • Thanks. However, it seems to me that both of the problems you mention can be solved more expressively by using a `volatile` field, or memory barriers. Correct me if I'm wrong. – dgmulf Dec 20 '14 at 22:56
  • 1
    Yes, they can be solved using volatile but that's harder to understand. Complicated primitives should be used if performance requirements demand it. – usr Dec 20 '14 at 23:36
  • 1
    One problem with using memory barriers in this specific case, is that it would mean using something in part 2 of the article that isn't explained until part 4. – Jon Hanna Dec 21 '14 at 00:34
4

If Joe removed both of those locks, what thread safety issue could arise?

It could lead to 'stale data', the reading code could cache it and only see an old value.

This usage of lock is a-typical, it is profiting from a side-effect of lock: it has an implied memory-barrier, and that prevents seeing an old copy. You would more usally see a volatile ProgressStatus _status; but volatile has its issues too.

You are right that the actual read and write operations don't reallly need a lock here (acessing a reference is atomic).

H H
  • 263,252
  • 30
  • 330
  • 514
  • Thanks - I suspected that a volatile field might do the trick. "`volatile` has its issues too" - can you please elaborate? – dgmulf Dec 20 '14 at 22:59