Tech Off Thread

20 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

A value class, eh?

Back to Forum: Tech Off
  • User profile image
    W3bbo

    I've got a class that inherits CollectionBase entitled "ProcessorCollection", it stores references to instantiated classes that implement IProcessor.

    In my Global I load and instantiate the IProcessors with info gleaned from a database and insert them into a ProcessorCollection which is then stored in Application["Processors"].

    Simple 'nuff, eh?

    Well, I just added the ability to add new classes to the collection without having to restart the application like so:

    
    ProcessorCollection PC = (ProcessorCollection)Application["Processors"];
    
    if(NewProcessorIsUploaded) {
        IProcessor Proc = //Some shiznitz to load and instantiate the class
    
        PC.Add(Proc);
    }
    
    for(int i=0; i<PC.Count; i++) {
         //output info on each processor
    }
    
    


    Sounds simple enough: Provided "PC" is just a reference to the collection located in Application["Processors"] then adding an item to PC's list would mean the item is stored there for good, right?

    Wrong!

    On susequent pageloads without uploading the processor the output procedure doesn't show the processor being in the list.

    But it does work when I do this:

    ProcessorCollection PC = (ProcessorCollection)Application["Processors"];
    
    if(NewProcessorIsUploaded) {
        IProcessor Proc = //Some shiznitz to load and instantiate the class
    
    
        PC.Add(Proc);
    
        Application["Processors"] = PC;
    }
    
    for(int i=0; i<PC.Count; i++) {
         //output info on each processor
    }
    


    So... uhm... why is Application["Processors"] being treated like a value-type?

  • User profile image
    Minh

    Perhaps a thread-optimize issue. Since Application could be called by hundres of threads simutaneously, for performance reason, each "get" is given it's own instance, so that Application doesn't have to monitor threading issues on each method access?

    Or maybe it's a ASP classic compatible issue. This is how it works in ASP classic, too.

  • User profile image
    geek2max

    What i think is that Application state should be shared through multiple worker processes so it has to be able to save it's state. Since you cannot know when an object gets modified, it saves its state only on that set.

    I had the same problem while I was designing a way to keep a persistent collection of serialized objects on disk while holding them in memory in a dictionary, the only way I found to keep the dictionary and objects files consistent was to set objectsa averytime... a bit tricky

  • User profile image
    sbc

    Remember to do Application.Lock() before modifying the application state (then Application.Unlock() afterwards).

  • User profile image
    candseeme

    W3bbo wrote:
     
        Application["Processors"] = PC;

    So... uhm... why is Application["Processors"] being treated like a value-type?



    Because it is a value type mr smart

  • User profile image
    bitmask

    Minh wrote:
    Perhaps a thread-optimize issue. Since Application could be called by hundres of threads simutaneously, for performance reason, each "get" is given it's own instance, so that Application doesn't have to monitor threading issues on each method access?


    There is only a single instance of application state. 

  • User profile image
    bitmask

    geek2max wrote:

    What i think is that Application state should be shared through multiple worker processes so it has to be able to save it's state. Since you cannot know when an object gets modified, it saves its state only on that set.



    Application state is in-process only. There is one instance of the collection per application (app domain) in the worker process.

  • User profile image
    bitmask

    Can you share the details of your collection class? Something seems odd.

    If I put the following into a web form and click Refresh, the list of timestamps keeps growing.

    protected void Page_Load(object sender, EventArgs e)
    {
        MyCollection list = Application["MyCollection"]
                              as MyCollection;
        if (list == null)
        {
            list = new MyCollection();
            Application["MyCollection"] = list;
        }

        foreach (string s in list)
        {
            Response.Write(s + "<br/>");
        }

        list.Add(DateTime.Now.ToLongTimeString());
        
    }

    MyCollection is a simple VB class:

    Public Class MyCollection
        Inherits CollectionBase

        Public Function Add(ByVal value As String) As Integer
            Return List.Add(value)
        End Function

    End Class
  • User profile image
    footballism

    W3bbo wrote:

    So... uhm... why is Application["Processors"] being treated like a value-type?

    Yep, your assumption to some extent is right, but actually HttpApplicationState is not a value type, it's still a reference type, because HttpApplicationState inherits NameObjectCollectionBase which is a Hashtable based collection. when you retrieve an entry from HttpApplicationState collection, for instance:
    ProcessorCollection pc = (ProcessorCollection) Application["Processors"];
    the HttpApplicationState will internally end up calling Hashtable's get_Item(Object key) method. in get_Item method,the hash code for the key object will be abtained first,this hash code identifies the Hashtable.bucket that is now searched looking for a stored key object that matches the specified key object, when a match is found,it will return the value corresponding to the specified key object, the pseudo code for this operation is something like the  following:
    public virtual Object  get_Item(Object key)
    {
        Hashtable.bucket[] buckets = this.buckets;
        foreach(Hashtable.bucket b in buckets)
        {
           if(this.KeyEquals(b.key, key))
           {
              return b.Val;
           }
        }

        return null;
    }
    the definition for Hashtable.bucket type is something like the following:
    private struct bucket
    {
        public Object key;
        public Object val;
    }

    because Hashtable.bucket is a struct, which is a value type, so every time you retrieve an object from Hashtable based collection, you actually end up having a private copy of that object.

    I think why Microsoft implements the Hashtable collection the way it is now is basically for thread-safe purpose, so every time you want to set new value to the HttpApplicationState collection entry, you have to lock it first, for instance:
    lock(Application.GetType())
    {
        Application["Processors"] = pc;
    }

    Sheva

  • User profile image
    W3bbo

    footballism wrote:
    W3bbo wrote:
    So... uhm... why is Application["Processors"] being treated like a value-type?

    Yep, your assumption to some extent is right, but actually HttpApplicationState is not a value type, it's still a reference type, because HttpApplicationState inherits NameObjectCollectionBase which is a Hashtable based collection. when you retrieve an entry from HttpApplicationState collection, for instance:
    ProcessorCollection pc = (ProcessorCollection) Application["Processors"];
    the HttpApplicationState will internally end up calling Hashtable's get_Item(Object key) method. in get_Item method,the hash code for the key object will be abtained first,this hash code identifies the Hashtable.bucket that is now searched looking for a stored key object that matches the specified key object, when a match is found,it will return the value corresponding to the specified key object, the pseudo code for this operation is something like the  following:
    public virtual Object  get_Item(Object key)
    {
        Hashtable.bucket[] buckets = this.buckets;
        foreach(Hashtable.bucket b in buckets)
        {
           if(this.KeyEquals(b.key, key))
           {
              return b.Val;
           }
        }

        return null;
    }
    the definition for Hashtable.bucket type is something like the following:
    private struct bucket
    {
        public Object key;
        public Object val;
    }

    because Hashtable.bucket is a struct, which is a value type, so every time you retrieve an object from Hashtable based collection, you actually end up having a private copy of that object.

    I think why Microsoft implements the Hashtable collection the way it is now is basically for thread-safe purpose, so every time you want to set new value to the HttpApplicationState collection entry, you have to lock it first, for instance:
    lock(Application.GetType())
    {
        Application["Processors"] = pc;
    }

    Sheva


    Thanks for clearing that one up footballism Smiley

  • User profile image
    TomasDeml

    footballism wrote:

    lock(Application.GetType())
    {
        Application["Processors"] = pc;
    }


    I think it's not very good to lock on a Type, you should use some sort of a sync object instead...

    lock(this.SyncObject)
    {
        ...
    }
    



  • User profile image
    Minh

    footballism wrote:

    the definition for Hashtable.bucket type is something like the following:
    private struct bucket
    {
        public Object key;
        public Object val;
    }


    I still don't understand this. If a struct is capable of holding a reference to an object on the global heap, and it's simply returning b.val, then manipulating b.val shouldn't required putting it back into Application. Maybe I'm thick, but I think there's more going on than this.

  • User profile image
    bitmask

    footballism wrote:
    the pseudo code for this operation is something like the  following:
    public virtual Object  get_Item(Object key)
    {
        Hashtable.bucket[] buckets = this.buckets;
        foreach(Hashtable.bucket b in buckets)
        {
           if(this.KeyEquals(b.key, key))
           {
              return b.Val;
           }
        }

        return null;
    }



    It wouldn't be a Hashtable if the code had to loop through the entire collection. Lookups are done using a hash of the incoming key.

    footballism wrote:


    because Hashtable.bucket is a struct, which is a value type, so every time you retrieve an object from Hashtable based collection, you actually end up having a private copy of that object.



    This doesn't explain the behavior W3bbo is seeing. He says he is putting an object reference into application state, so what he pulls out is a copy of that reference. In other words, he should still reference the same object, as my sample code demonstrated.

    footballism wrote:


     so every time you want to set new value to the HttpApplicationState collection entry, you have to lock it first, for instance:
    lock(Application.GetType())
    {
        Application["Processors"] = pc;
    }



    No, the locks are already in the implementation as documented in MSDN ("this type is safe for multithreaded operations"). You only need to use Application.Lock if you need the lock to span multiple operations. This doesn't mean W3bbo's processor collection is thread safe, only the application state collection.

  • User profile image
    footballism

    bitmask wrote:
    footballism wrote: the pseudo code for this operation is something like the  following:
    public virtual Object  get_Item(Object key)
    {
        Hashtable.bucket[] buckets = this.buckets;
        foreach(Hashtable.bucket b in buckets)
        {
           if(this.KeyEquals(b.key, key))
           {
              return b.Val;
           }
        }

        return null;
    }



    It wouldn't be a Hashtable if the code had to loop through the entire collection. Lookups are done using a hash of the incoming key.


    Yep, the lookups are done by comparing hash code as I've said in my previous post, I just across it out for demonstration purpose.

    bitmask wrote:


    footballism wrote:

     so every time you want to set new value to the HttpApplicationState collection entry, you have to lock it first, for instance:
    lock(Application.GetType())
    {
        Application["Processors"] = pc;
    }



    No, the locks are already in the implementation as documented in MSDN ("this type is safe for multithreaded operations"). You only need to use Application.Lock if you need the lock to span multiple operations. This doesn't mean W3bbo's processor collection is thread safe, only the application state collection.


    This is what I read from MSDN documentation:

    You should always modify application state data within a lock statement unless you have set some other type of lock. For more information, see Synchronizing Data for Multithreading.


    Sheva

  • User profile image
    footballism

    Minh wrote:
    footballism wrote:
    the definition for Hashtable.bucket type is something like the following:
    private struct bucket
    {
        public Object key;
        public Object val;
    }


    I still don't understand this. If a struct is capable of holding a reference to an object on the global heap, and it's simply returning b.val, then manipulating b.val shouldn't required putting it back into Application. Maybe I'm thick, but I think there's more going on than this.


    After re-examining what I've posted previously, I decide to write some test code to verify whether or not I get it right:

    using System;
    using System.Collections;

    namespace ValueTypeTest
    {
        public class ProcessorCollection : CollectionBase
        {
            public void Add(Object obj)
            {
                List.Add(obj);
            }
        }

        public class BucketRefType
        {
            public Object Value;
            public Int32 Index;

            public BucketRefType(Object value, Int32 index)
            {
                this.Value = value;
                this.Index = index;
            }
        }

        public struct BucketValueType
        {
            public Object Value;
            public Int32 Index;

            public BucketValueType(Object value, Int32 index)
            {
                this.Value = value;
                this.Index = index;
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                BucketValueType bucketValueType1 = new BucketValueType(new ProcessorCollection(), 1);
                ProcessorCollection pc1 = (ProcessorCollection)bucketValueType1.Value;
                pc1.Add(new Object());

                Console.WriteLine("For BucketValueType:");
                Console.WriteLine("Equals method returns {0}", bucketValueType1.Value.Equals(pc1));
                Console.WriteLine("Object.ReferenceEquals methods returns {0}", Object.ReferenceEquals(bucketValueType1.Value, pc1).ToString());

                BucketRefType bucketRefType1 = new BucketRefType(new ProcessorCollection(), 1);
                ProcessorCollection pc2 = (ProcessorCollection)bucketRefType1.Value;
                pc2.Add(new Object());

                Console.WriteLine("For BucketRefType:");
                Console.WriteLine("Equals method returns {0}", bucketRefType1.Value.Equals(pc2));
                Console.WriteLine("Object.ReferenceEquals methods returns {0}", Object.ReferenceEquals(bucketRefType1.Value, pc2).ToString());
                Console.ReadLine();
            }
        }
    }

    and the result is:
    For BucketValueType:
    Equals method returns True
    Object.ReferenceEquals methods returns True
    For BucketRefType:
    Equals method returns True
    Object.ReferenceEquals methods returns True

    Sorry, W3bbo and all others, I AM CONFUSED NOW[C]

    PS: I will try to make it clear to myself:P

    Sheva

  • User profile image
    Frank Hileman

    Sorry, Footballism, your explanation is wrong. The structs hold references. It does not magically turn those references into value types -- they are still reference types. Microsoft's Hashtable is designed to work with references.

  • User profile image
    footballism

    Frank Hileman wrote:

    Sorry, Footballism, your explanation is wrong. The structs hold references. It does not magically turn those references into value types -- they are still reference types. Microsoft's Hashtable is designed to work with references.


    Yep, I've known that, please see my test code above.

    Sheva

  • User profile image
    Frank Hileman

    We need more code to figure this out. Post your code for the collections, Application, etc.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.