multithreading : two easy questions

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Harold Howe

    multithreading : two easy questions

    Howdy,

    1- Are property reads in effect volatile? Or is the compiler allowed to
    optimize property reads away? ie

    class foo
    {
    public int bar
    {
    get { return m_bar;}
    set { m_bar = value;}
    }
    private int m_bar;
    }

    ....

    foo f = new foo();
    f.bar=1000;
    ....// make f available to another thread
    while (f.bar==1000)
    {
    ...
    }

    On each pass through the loop, am I guaranteed that the compiler will
    requery the get routine for the bar property? If so, then properties are
    logically volatile. If not, then my loop will never end, even if a
    background thread sets f.bar to a different value.

    2- Are string assignments atomic? Hejlsberg's c# book claims that
    assignments to ref types are atomic. Strings are references, but they
    often don't feel like it. In searching these groups, I read several
    posters that claim that string assignments are not atomic. Hence my doubt.

    I am asking this question because I am trying to create a thread safe
    object that has a string property. If string assignments are not atomic,
    then returning a string value from a property getter is not thread safe,
    and I will need a lock.

    public String Value
    {
    get { return m_Value; // atomic??? }

    // or
    get
    {
    String result;
    lock(this)
    {
    result = m_Value;
    }
    return result;
    }
    }

    I would like to avoid the lock when reading if possible.

    h^2

    keywords: read, write, atomicity, assignment, properties.
  • Jon Skeet [C# MVP]

    #2
    Re: multithreading : two easy questions

    Harold Howe <hhowe@bcbdev.c om> wrote:[color=blue]
    > 1- Are property reads in effect volatile?[/color]

    No. You need to synchronize them. This isn't to do with properties
    though - it's to do with variables. The property can run perfectly
    reasonably, but if the thread doesn't notice the new version of the
    variable, the property will continue to return the old value.
    [color=blue]
    > 2- Are string assignments atomic? Hejlsberg's c# book claims that
    > assignments to ref types are atomic. Strings are references, but they
    > often don't feel like it. In searching these groups, I read several
    > posters that claim that string assignments are not atomic. Hence my doubt.[/color]

    They're atomic, but not necessarily volatile.
    [color=blue]
    > I am asking this question because I am trying to create a thread safe
    > object that has a string property. If string assignments are not atomic,
    > then returning a string value from a property getter is not thread safe,
    > and I will need a lock.
    >
    > public String Value
    > {
    > get { return m_Value; // atomic??? }
    >
    > // or
    > get
    > {
    > String result;
    > lock(this)
    > {
    > result = m_Value;
    > }
    > return result;
    > }
    > }
    >
    > I would like to avoid the lock when reading if possible.[/color]

    Well, for one thing you don't need to have a separate variable - you
    can just return from within the lock. However, the above isn't thread-
    safe - if another thread sets a different value for m_Value, there's no
    guarantee that the first thread will see it. However, atomicity
    requires that it will either see the old value or the new value - that
    much you can rely on.

    See http://www.pobox.com/~skeet/csharp/threads for more information.

    --
    Jon Skeet - <skeet@pobox.co m>
    Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

    If replying to the group, please do not mail me too

    Comment

    • Harold Howe

      #3
      Re: multithreading : two easy questions

      Jon Skeet [C# MVP] wrote:
      [color=blue]
      > Harold Howe <hhowe@bcbdev.c om> wrote:
      >[color=green]
      >>1- Are property reads in effect volatile?[/color]
      >
      >
      > No. You need to synchronize them.[/color]

      Where? Why? Here is a more complete example that actually shows a
      background thread. The main thread sits and prints periods until the
      background thread sets a property to 100.

      Where is a lock necessary in this example? In light of the fact that
      integer reads and writes are atomic, I see no need for a lock here. Even
      though m_value is not volatile, aren't we guaranteed that the set
      fuction will commit pending writes upon return? Please elaborate if you
      disagree.

      For the sake of discussion, assume the while loop can safely run one
      full time while Value>=100.

      using System;
      using System.Threadin g;

      namespace Test
      {
      internal class Test
      {
      static int m_value;
      static int Value
      {
      get {return m_value;}
      set {m_value = value;}
      }

      static void threadfunc()
      {
      for(int i=0; i<=100; ++i)
      {
      Value = i;
      Thread.Sleep(10 0);
      }
      }

      static void Main()
      {
      Console.WriteLi ne("Interlocke d test.");
      Thread thread = new Thread(new ThreadStart(thr eadfunc));
      thread.Start();
      while(Value != 100)
      {
      Console.Write(' .');
      }
      }
      }
      }
      [color=blue]
      > The property can run perfectly
      > reasonably, but if the thread doesn't notice the new version of the
      > variable, the property will continue to return the old value.[/color]

      Why wouldn't the thread notice the new value in the variable? I realize
      that the private field is not volatile, but once the setter has
      returned, aren't we guaranteed that all writes have been committed to
      main memory?
      [color=blue]
      > (in reference to string atomicity)
      > However, the above isn't thread-
      > safe - if another thread sets a different value for m_Value, there's no
      > guarantee that the first thread will see it.[/color]

      Could you explain why? I don't mean in the case where the property get
      function was called, fetched the old value and was pre-empted by a
      thread switch before it could return it. In this case, I understand that
      the old value will still be returned. That I don't care about.

      H^2

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: multithreading : two easy questions

        Harold Howe <hhowe@bcbdev.c om> wrote:[color=blue][color=green]
        > > Harold Howe <hhowe@bcbdev.c om> wrote:
        > >[color=darkred]
        > >>1- Are property reads in effect volatile?[/color]
        > >
        > > No. You need to synchronize them.[/color]
        >
        > Where?[/color]

        That's up to you - you could either make the properties themselves
        thread-safe by including locking in there, or you can lock in the
        calling code.
        [color=blue]
        > Why?[/color]

        Because otherwise one thread can change the value of the variable (via
        the property) and another thread might still see the old value because
        there's nothing to say it can't unless you've got explicit memory
        barriers in there.
        [color=blue]
        > Here is a more complete example that actually shows a
        > background thread. The main thread sits and prints periods until the
        > background thread sets a property to 100.
        >
        > Where is a lock necessary in this example? In light of the fact that
        > integer reads and writes are atomic, I see no need for a lock here.[/color]

        That's because you're confusing atomicity with volatility. They're very
        different concepts.
        [color=blue]
        > Even though m_value is not volatile, aren't we guaranteed that the set
        > fuction will commit pending writes upon return?[/color]

        No - where do you get that idea from? The CLR doesn't make any such
        guarantee - and even if the pending write was made, there's no
        guarantee that the reading thread would make a fresh read rather than
        using a cached version.
        [color=blue]
        > Please elaborate if you disagree.[/color]

        See http://www.pobox.com/~skeet/csharp/t...latility.shtml
        [color=blue][color=green]
        > > The property can run perfectly
        > > reasonably, but if the thread doesn't notice the new version of the
        > > variable, the property will continue to return the old value.[/color]
        >
        > Why wouldn't the thread notice the new value in the variable? I realize
        > that the private field is not volatile, but once the setter has
        > returned, aren't we guaranteed that all writes have been committed to
        > main memory?[/color]

        No, nor that fresh writes are read, either.
        [color=blue][color=green]
        > > (in reference to string atomicity)
        > > However, the above isn't thread-
        > > safe - if another thread sets a different value for m_Value, there's no
        > > guarantee that the first thread will see it.[/color]
        >
        > Could you explain why? I don't mean in the case where the property get
        > function was called, fetched the old value and was pre-empted by a
        > thread switch before it could return it. In this case, I understand that
        > the old value will still be returned. That I don't care about.[/color]

        The JIT compiler may have enregistered the variable, for instance -
        unless there's a thread barrier, there's nothing to say that the CLR
        needs to read the newest value of the variable.

        Please read the article I linked above (and in my previous post) - it
        has much more information, and I don't want to repeat it all here.

        --
        Jon Skeet - <skeet@pobox.co m>
        Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

        If replying to the group, please do not mail me too

        Comment

        • Harold Howe

          #5
          Re: multithreading : two easy questions

          [color=blue][color=green]
          >>Even though m_value is not volatile, aren't we guaranteed that the set
          >>fuction will commit pending writes upon return?[/color]
          >
          >
          > No - where do you get that idea from?[/color]

          A combination of things:

          1- Static fields are allocated on an app domain basis. Hence, all load
          and store IL instructions for the static field will read and write the
          same memory location (across threads). 12.3.1 puts this in writing.
          Furthermore, a modification of a static field is considered a side effect.

          2- 12.6.4 "Conforming implementations of the CLI are free to execute
          programs using any technology that guarantees, within a single thread of
          execution, that side-effects and exceptions generated by a thread are
          visible in the order specified by the CIL."

          "An optimizing compiler is free to reorder side-effects and synchronous
          exceptions to the extent that this reordering does not change any
          observable program behavior."

          The set method for the property has a side effect: ie it writes to a
          static field. This side effect can be re-orderded with other side
          effects in that thread, so long as observed behavior is not altered.
          From a practical standpoint, this re-ordering of side effects can only
          happen within a method call. The method has no idea what is going to
          happen after it returns, so it has no choice but to commit any pending
          side effects to the static field via an stsfld IL instruction. The spec
          does not state this outright though.

          You also argued that the get method could fetch the value from some
          cached location rather than the reading the static field. Based on
          section, 12.3.2 (method state), I don't think this is possible. If a
          method were to cache the value for a static field across calls to the
          same method, where would it store the value? For a given method state,
          there are three potential places: the evaluation stack, the local
          variables array, and the local memory pool.

          By definition, the value can't be cached in the evaluation stack,
          because it is empty on method entry and must be empty on return of the
          method. The local memory pool is also reclaimed on method exit, so its out.

          That leaves the local variables array. It is conceivable that an int
          could be cached there, but the spec makes no guarantees regarding the
          contents of the array upon return and re-entry. Indeed, a simple test
          reveals that the contents are in fact *not* preserved.

          On entry, the get method has no choice but to use a ldsfld IL
          instruction to read the value from memory.

          [color=blue][color=green]
          >>Please elaborate if you disagree.[/color]
          >
          > See http://www.pobox.com/~skeet/csharp/t...latility.shtml[/color]

          I read your article before I posted my followup, and i believe that it
          addresses a different case. Namely, how non-volatile field variables can
          be cached on a method's evaluation stack while the method is executing,
          and how side effects can be delayed prior to a method's return. This
          scenario is different from mine, IMO.

          In essense, you are claiming that for the following code:

          class Test
          {
          static int m_value;
          static int Value
          {
          get {return m_value;}
          set {m_value = value;}
          }
          }

          that the get method could read and return m_value somehow without using
          ldslfd to load the value from memory, and that the side effect in the
          set method could be delayed until after the setter returns. I disagree
          with both assertions, but I do not think that I have enough evidence to
          prove it outright.

          Since I can't prove it completely, I think it may make sense to declare
          the field as volatile. I do not agree with the article's suggestion of
          using lock statements. They seem excessive for values that can be
          assigned and read atomically. I understand that they provide
          volatileread, volatilewrite semantics, but I can get that without the
          overhead of a lock.

          Thanks for your insight.

          H^2

          Comment

          • Jon Skeet [C# MVP]

            #6
            Re: multithreading : two easy questions

            Harold Howe <hhowe@bcbdev.c om> wrote:[color=blue]
            >[color=green][color=darkred]
            > >>Even though m_value is not volatile, aren't we guaranteed that the set
            > >>fuction will commit pending writes upon return?[/color]
            > >
            > >
            > > No - where do you get that idea from?[/color]
            >
            > A combination of things:
            >
            > 1- Static fields are allocated on an app domain basis. Hence, all load
            > and store IL instructions for the static field will read and write the
            > same memory location (across threads). 12.3.1 puts this in writing.
            > Furthermore, a modification of a static field is considered a side effect.[/color]

            Sure.
            [color=blue]
            > 2- 12.6.4 "Conforming implementations of the CLI are free to execute
            > programs using any technology that guarantees, within a single thread of
            > execution, that side-effects and exceptions generated by a thread are
            > visible in the order specified by the CIL."[/color]

            The important thing in there is "within a single thread of execution".
            That doesn't say anything about what happens in different threads, or
            when things are visible in other threads.
            [color=blue]
            > "An optimizing compiler is free to reorder side-effects and synchronous
            > exceptions to the extent that this reordering does not change any
            > observable program behavior."[/color]

            Again, this is within a single thread. In other words, it can't reorder

            if (x==null || x.Length==0)

            to try to access x.Length before testing whether x is null. There's no
            guarantee about ordering of side-effects as seen by other threads.
            [color=blue]
            > The set method for the property has a side effect: ie it writes to a
            > static field. This side effect can be re-orderded with other side
            > effects in that thread, so long as observed behavior is not altered.
            > From a practical standpoint, this re-ordering of side effects can only
            > happen within a method call. The method has no idea what is going to
            > happen after it returns, so it has no choice but to commit any pending
            > side effects to the static field via an stsfld IL instruction. The spec
            > does not state this outright though.[/color]

            Although the method itself has no idea what's going to happen, it
            doesn't need to - it doesn't guarantee that the write will be committed
            to main memory until the next write memory barrier, which is fine -
            another method can be responsible for that, if necessary.
            [color=blue]
            > You also argued that the get method could fetch the value from some
            > cached location rather than the reading the static field. Based on
            > section, 12.3.2 (method state), I don't think this is possible. If a
            > method were to cache the value for a static field across calls to the
            > same method, where would it store the value? For a given method state,
            > there are three potential places: the evaluation stack, the local
            > variables array, and the local memory pool.[/color]

            Consider inlined method calls which may end up enregistering variables.
            Consider processor caches on multi-processor systems - the code may be
            writing to main memory as far as it's concerned, but the cache may
            decide not to write it back to the actual main memory until some other
            code executes to make sure there's a write memory barrier. (This may
            not happen on x86, but that's not to say it won't happen on other
            processors...)
            [color=blue]
            > By definition, the value can't be cached in the evaluation stack,
            > because it is empty on method entry and must be empty on return of the
            > method. The local memory pool is also reclaimed on method exit, so its out.
            >
            > That leaves the local variables array. It is conceivable that an int
            > could be cached there, but the spec makes no guarantees regarding the
            > contents of the array upon return and re-entry. Indeed, a simple test
            > reveals that the contents are in fact *not* preserved.[/color]

            Simple tests don't say what future implementations on different
            processors. I agree that on current x86 processors, with the current
            implementation, you're probably okay. I don't like to rely on
            "probably" though.
            [color=blue]
            > On entry, the get method has no choice but to use a ldsfld IL
            > instruction to read the value from memory.[/color]

            The IL isn't what's actually executed though - it's what the JIT
            compiler decides to do that's important.
            [color=blue][color=green][color=darkred]
            > >>Please elaborate if you disagree.[/color]
            > >
            > > See http://www.pobox.com/~skeet/csharp/t...latility.shtml[/color]
            >
            > I read your article before I posted my followup, and i believe that it
            > addresses a different case. Namely, how non-volatile field variables can
            > be cached on a method's evaluation stack while the method is executing,
            > and how side effects can be delayed prior to a method's return. This
            > scenario is different from mine, IMO.[/color]

            I'm not addressing that case particularly - I'm addressing *all* cases.
            There just *isn't* any guarantee that you'll see a write from one
            thread in another one unless the appropriate memory barriers are there.
            [color=blue]
            > In essense, you are claiming that for the following code:
            >
            > class Test
            > {
            > static int m_value;
            > static int Value
            > {
            > get {return m_value;}
            > set {m_value = value;}
            > }
            > }
            >
            > that the get method could read and return m_value somehow without using
            > ldslfd to load the value from memory, and that the side effect in the
            > set method could be delayed until after the setter returns. I disagree
            > with both assertions, but I do not think that I have enough evidence to
            > prove it outright.[/color]

            I'm claiming that the spec doesn't guarantee it. I think most
            implementations on most processors will be fine, but I prefer to go
            with what the spec requires.

            As an example of how extreme this can get, I was talking with someone
            once about a multi-system (not just multi-processor) JVM implementation
            once. "Main memory" there was accessed via the network - so nothing
            wanted to read or write from/to "main memory" unless it absolutely had
            to. The normal "main memory" of each system actually just acted as a
            cache. Now obviously the memory model of the JVM is slightly different
            to the .NET one, but the same kind of thing can apply.
            [color=blue]
            > Since I can't prove it completely, I think it may make sense to declare
            > the field as volatile. I do not agree with the article's suggestion of
            > using lock statements. They seem excessive for values that can be
            > assigned and read atomically. I understand that they provide
            > volatileread, volatilewrite semantics, but I can get that without the
            > overhead of a lock.[/color]

            Yes, you can. However, you then need to think a bit about when you need
            volatile and when you need a lock. I personally prefer to stick to
            using locks all the time unless I find they're a significant
            performance problem - which I never have.

            --
            Jon Skeet - <skeet@pobox.co m>
            Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

            If replying to the group, please do not mail me too

            Comment

            Working...