C# Updateing object references and multithreading -


after reading how it, i'm quite confused.

so here want do: have datastructure/object holds kinds of information. tread datastructure if immutable. whenever need update information, make deepcopy , changes it. swap old , newly created object.

now don't know how right.

let's @ side of reader/consumer threads.

myobj temp = datasource; var = temp.a; ... // many instructions var b = temp.b; .... 

as understand reading references atomic. don't need volatile or locking assign current reference of datasource temp. garbage collection. understand gc has kind of reference counter know when free memory. when thread updates datasource @ moment when datasource assigned temp, gc increase counter on right memory block? other thing compiler/clr optimization. assign datasource temp , use temp access data members. clr do? make copy of datasource or optimizer use datasource access .a , .b? let's assume between temp.a , temp.b lot's of instructions reference temp/datasource cannot held in cpu register. temp.b temp.b or optimized datasource.b because copy temp can optimized away. important if thread updates datasource point new object.

do need volatile, lock, readwriterlockslim, thread.memorybarrier or else? important thing me want make sure temp.a , temp.b access old datastructure when thread updates datasource newly created data structure. never change data inside existing structure. updates done creating copy, updating data , updating reference new copy of datastructre.


maybe 1 more question. if don't use volatile, how long take until cores on cpus see updated reference?


when comes volatile please have here: when should volatile keyword used in c#?


i have done little test programm:

namespace test1 {   public partial class form1 : form {     public form1() { initializecomponent(); }      sharedobj = new something();      private void button1_click(object sender, eventargs e) {       thread t = new thread(do);          // kick off new thread       t.start();                               // running writey()        (int = 0; < 1000; i++) {         reference = sharedobj;          int x = reference.x; // sharedobj.x;         system.threading.thread.sleep(1);         int y = reference.y; // sharedobj.y;          if (x != y) {           button1.text = x.tostring() + "/" + y.tostring();           update();         }       }     }      private void do() {       (int = 0; < 1000000; i++) {         somenewobject = sharedobj.clone(); // clone immutable         somenewobject.do();         sharedobj = somenewobject; // atomic       }     }   }    class {     public clone() { return (something)memberwiseclone(); }     public void do() { x++; system.threading.thread.sleep(0); y++; }     public int x = 0;     public int y = 0;   } } 

in button1_click there for-loop , inside for-loop access datastructure/object once using direct "shareobj" , once using temporarily created "reference". using reference enough make sure "var a" , "var b" initialized values same object.

the thing don't understand is, why "something reference = sharedobj;" not optimized away , "int x = reference.x;" not replaced "int x = sharedobj.x;"?

how compiler, jitter know not optimize this? or temporarily objects never optimized in c#?

but important: example running intended because correct or running intended accident?

as understand reading references atomic.

correct. limited property though. means reading reference work; you'll never bits of half old reference mixed bits of half new reference resulting in reference doesn't work. if there's concurrent change promises nothing whether old or new reference (what such promise mean?)

so don't need volatile or locking assign current reference of datasource temp.

maybe, though there cases can have problems.

but garbage collection. understand gc has kind of reference counter know when free memory.

incorrect. there no reference counting in .net garbage collection.

if there static reference object, not eligible reclamation.

if there active local reference object, not eligble reclamation.

if there reference object in field of object not eligible reclamation, not eligible reclamation, recursively.

there's no counting here. either there active strong reference prohibiting reclamation, or there isn't.

this has great many important implications. of relevance here there can never incorrect reference counting, since there no reference counting. strong references not disappear under feet.

the other thing compiler/clr optimization. assign datasource temp , use temp access data members. clr do? make copy of datasource or optimizer use datasource access .a , .b?

that depends on datasource , temp far whether local or not, , how used.

if datasource , temp both local, possible either compiler or jitter optimise assignment away. if both local though, both local same thread, isn't going impact multi-threaded use.

if datasource field (static or instance), since temp local in code shown (because initialised in code fragment shown) assignment cannot optimised away. 1 thing, grabbing local copy of field in possible optimisation, being faster several operations on local reference continually access field or static. there's not point having compiler or jitter "optimisation" makes things slower.

consider happens if not use temp:

var = datasource.a; ... // many instructions var b = datasource.b; 

to access datasource.a code must first obtain reference datasource , access a. afterwards obtains reference datasource , accesses b.

optimising not using local makes no sense, since there's going implicit local anyway.

and there simple fact fear have considered: after temp = datasource there's no assumption temp == datasource because there other threads changing datasource, it's not valid make optimisations predicated on temp == datasource.*

really optimisations concerned either not relevant or not valid , hence not going happen.

there case cause problems though. possible thread running on 1 core not see change datasource made thread changing on core. such if have:

/* thread */ datasource = null;  /* time has passed */  /* thread b */ var isnull = datasource == null; 

then there's no guarantee because thread had finished setting datasource null, thread b see this. ever.

the memory models in use in .net , in processors .net runs on (x86 , x86-64) prevent happening, in terms of possible future optimisations, that's possible. need memory barriers ensure thread a's publishing affects thread b's reading. lock , volatile both ways ensure that.

*one doesn't need multi-threaded not follow, though possible prove in particular cases there no single-thread changes break assumption. doesn't matter though, because multi-threaded case still applies.


Comments

Popular posts from this blog

qt - Using float or double for own QML classes -

Create Outlook appointment via C# .Net -

ios - Swift Array Resetting Itself -