0

My idea is to run a few operations asynchronously; I can guarantee that two operations will never run concurrently, but I can't guarantee that they will run on the same thread/CPU as the others.

// Example code
int myValue = 0;

ThreadPool.QueueUserWorkItem(state => {
    myValue++;

    ThreadPool.QueueUserWorkItem(state2 => {
        Console.WriteLine(myValue);
    });
});

Is the output guaranteed to be 1 even without locking?

Maybe a call to Thread.MemoryBarrier() is required before the Console.WriteLine(myValue)?

Or maybe myValue should be made volatile?

I'm not really used to multithreading programming without locking, I hope someone can solve my doubts.

Thanks!

EDIT:

What if I decide to use locking? Is this code guaranteed to output 1?

If yes, why? Could not the compiler decide to store myValue on the register of a CPU?

I have never actually had any problem with a code like this, but I've only run my programs on x86 and x64 CPUs so far. What about MONO, ARM, and other "esoteric" platforms?

// Example code
object lockMe = new object();
int myValue = 0;

ThreadPool.QueueUserWorkItem(state => {
    lock(lockMe) {
        myValue++;
    }

    ThreadPool.QueueUserWorkItem(state2 => {
        lock(lockMe) {
            Console.WriteLine(myValue);
        }
    });
});

Thanks again!

Fabio Iotti
  • 1,480
  • 1
  • 16
  • 20
  • `Console.WriteLine(myValue);` will always print `1`. But be aware that its not guaranteed that `myValue` will already be incremented after you executed `ThreadPool.QueueUserWorkItem(...);` – nozzleman Nov 10 '15 at 06:57
  • 1
    To "Or maybe `myValue` should be made `volatile`?" - http://stackoverflow.com/a/17530556/2026276 – Bauss Nov 10 '15 at 07:08
  • @nozzleman May I ask how can the second operation (`Console.WriteLine`) be guaranteed to see the updated version of `myValue`? Could `myValue` not have been cached in a register of the CPU that executed the first operation (`myValue++`)? Forgive my uncertainty. – Fabio Iotti Nov 10 '15 at 07:09
  • 2
    Why on earth do you want to avoid taking a lock? An uncontended lock is about a dozen nanoseconds. Almost no one can do low lock programming correctly, and almost no one needs to; why are you trying to do so? – Eric Lippert Nov 10 '15 at 08:01
  • I never actually wanted to do lock-free programming, I just wanted to explore the alternatives, but the more I read what people writes on the Internet the more I get convinced to abort this kind of creepy-programming and stick to the "old-fashioned" locks. :) Then I have just one more doubt, I will update the original question now... – Fabio Iotti Nov 10 '15 at 08:14

1 Answers1

1

ThreadPool.QueueUserWorkItem, like any other library functions which executes code in the other thread, garantees that this code will see every modification, visible by the current thread up to the function call.

Because myValue++ precedes ThreadPool.QueueUserWorkItem() in program order, result of value's modification is seen by the caller thread. So Console.WriteLine(myValue) will definitely see updated value.

Locking, volatile modifier are completely unnecessary in that case.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153