Kent
Kent

Reputation: 59

Null Exception accessing another class object

Forgive me, I'm learning C# and object-oriented programming. I am running two threads. Thread #2 calls a different class method. This method assigns an object's data value. Thread #1 unsuccessfully attempts to access the object's data value that Thread #2 assigned. The object's data value in Thread #1 is null. How do I access this object and all its assigned data values? I basically want to save the data variables from Thread #2 classes and access them from a Thread #1 class. It appears an object and it's data member values generated in a Thread #2 class are null when I leave the class and then try to access the same object in a Thread #1 class. Can I still save the instantiated object values in my example or should I declare things as static? Below is some of my code to illustrate my problem. Thank you for anyone that can recommend or illustrate how to resolve this.

// this is a main operating class that:  1) starts two threads and 2) trys to access the Thread #2 Lru_SetChanFreq class object data from Thread #1 Lru_operations class    
public class Lru_operation
{
        [STAThread]
        static void Main()
        {
            // starts a separate thread #2
            Lru_Listen LruListen1 = new Lru_Listen();
            Thread LruListenThread = new Thread(new ThreadStart(LruListen1.ListenForAag));
            LruListenThread.Start();

            while(!LruListenThread.IsAlive)
                ;
            Thread.Sleep(1);

            // follows the main thread #1 
            Lru_operation LruOpX = new Lru_operation();         
            LruOpX.LruOperation();                      
        }

        // this is where main thread #1 operates
        public void LruOperation()
        {       
            // create object to access object data from thread #2 Lru_SetChanFreq class 
            Lru_SetChanFreq SetChFrq = new Lru_SetChanFreq();
            try
            {
                // do stuff

                // ERROR:  SetChFrq.LruSetFrq.RxFreq2 = null and then catches an exception to go below.
                // Why is this happening if Thread #2 previously sets RxFreq2 = 405.1?
                Console.WriteLine("LruSetFrq.RxFreq2 = {0}", SetChFrq.LruSetFrq.RxFreq2);

                // do more stuff

            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message, "connection terminated",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

}



// this is called from thread #2.  It's object is used by thread #1   
public class Lru_SetChanFreq
{
        #region fields
        private string rxFreq2;
        private Lru_SetChanFreq mLruSetFrq;
        #endregion fields

        #region Properties
        public Lru_SetChanFreq LruSetFrq
        {
            get { return mLruSetFrq; }
            set { mLruSetFrq = value; }
        }

        public string RxFreq2
        {
            get { return rxFreq2; }
            set { rxFreq2 = value; Console.WriteLine("rxFreq2 = {0}", rxFreq2); }
        }
        #endregion Properties

        #region methods 
        public Lru_SetChanFreq()
        {
        }

        public void SetFreq()
        {   
            mLruSetFrq = new Lru_SetChanFreq();
            mLruSetFrq.RxFreq2 = "405.1";

            // I confirmed that LruSetFrq.RxFreq2 = 405.1
            Console.WriteLine("LruSetFrq.RxFreq2 = {0}", LruSetFrq.RxFreq2);

            // do stuff
        }
        #endregion methods
}


// this is starting point of thread #2   
public class Lru_Listen
    {
        #region Fields
        // stuff
        #endregion Fields

        #region Properties
        // stuff
        #endregion Properties

        #region Methods   
        public void ListenForAag()
        {
            // do stuff
            LruListenAccReq();                  
        }

        public void LruListenAccReq()
        {
            // do stuff
            LruShowRequestData(request);
        }

        public void LruShowRequestData(// stuff )
        {
            Lru_SetChanFreq SetChanFreq = new Lru_SetChanFreq();        
            SetChanFreq.SetFreq();   // calls to another class method                           
        } 
        #endregion Methods
    }
} 

Upvotes: 0

Views: 366

Answers (2)

Douglas
Douglas

Reputation: 54897

Your issue is that you are initializing and accessing distinct Lru_SetChanFreq instances in your two threads. You should initialize just one, assign it to a class field, and then access the same instance from the other thread. Here is a trimmed-down version of your code that does that:

public class Lru_operation
{
    [STAThread]
    static void Main()
    {
        Lru_Listen LruListen1 = new Lru_Listen();

        // Run LruListen1 on Thread 2
        Thread LruListenThread = new Thread(new ThreadStart(LruListen1.ListenForAag));
        LruListenThread.Start();

        // Wait for its operation to complete
        // There is no need to wait for the thread to terminate
        LruListen1.readyEvent.WaitOne();

        // Read the Lru_SetChanFreq initialized from LruListen1,
        // and continue processing it on Thread 1
        Lru_operation LruOpX = new Lru_operation();         
        LruOpX.LruOperation(LruListen1.SetChanFreq);                      
    }

    public void LruOperation(Lru_SetChanFreq setChanFreq)
    {
        // Access the original Lru_SetChanFreq instance received as parameter
    }
}    

// this is starting point of thread #2   
public class Lru_Listen
{
    // Declare Lru_SetChanFreq as a field so as to access it externally
    internal Lru_SetChanFreq SetChanFreq;

    // Our thread synchronization event
    internal ManualResetEvent readyEvent = new ManualResetEvent(false);

    public void LruShowRequestData(// stuff )
    {
        this.SetChanFreq = new Lru_SetChanFreq();        
        SetChanFreq.SetFreq();   // calls to another class method  

        // Signal that we are ready                 
        readyEvent.Set();
    }
}

Update: I've edited my code to introduce proper thread synchronization (to replace the OP's while (LruListenThread.IsAlive) and Thread.Sleep(1)). This consists of three parts:

  1. Creating a ManualResetEvent instance that can be accessed by both threads.
  2. Calling WaitOne from Thread 1, in order to make it wait.
  3. Calling Set from Thread 2 once it completes initializing your Lru_SetChanFreq, thereby signalling to Thread 1 that it may proceed.

Upvotes: 0

Henk Holterman
Henk Holterman

Reputation: 273621

Your 2 Threads each make an instance of Lru_SetChanFreq . The 2 instances are not related or coupled. Setting a value on one thread (SetChanFreq.SetFreq()) has no bearing on the other thread.

A few points:

  • Try to pick meaningful, readable names. Prefixes like Lru_ have a negative impact on readability.
  • Study the meaning of object-instance (vs static) first. Leave threading alone until you have a good grasp of objects and memory management.
  • In the end you probably won't want to use Threads at all, ThreadPool and Task are more efficient and convenient.

Upvotes: 3

Related Questions