Null Exception访问另一个类对象

时间:2014-01-13 21:15:31

标签: c# multithreading

原谅我,我正在学习C#和面向对象的编程。我正在运行两个线程。线程#2调用不同的类方法。此方法分配对象的数据值。线程#1未成功尝试访问线程#2分配的对象的数据值。线程#1中对象的数据值为空。如何访问此对象及其分配的所有数据值?我基本上想要从Thread#2类保存数据变量并从Thread#1类访问它们。它似乎是一个对象,当我离开该类然后尝试访问Thread#1类中的同一对象时,它在Thread#2类中生成的数据成员值为null。我仍然可以在我的示例中保存实例化的对象值,还是应该将事物声明为静态?下面是我的一些代码来说明我的问题。感谢任何可以推荐或说明如何解决此问题的人。

// 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
    }
} 

2 个答案:

答案 0 :(得分:3)

你的2个主题各自构成Lru_SetChanFreq的实例。这2个实例不相关或耦合。在一个线程(SetChanFreq.SetFreq())上设置值与另一个线程无关。

几点:

  • 尝试选择有意义的,可读的名称。像Lru_这样的前缀会对可读性产生负面影响。
  • 首先研究object-instance(vs static)的含义。在您掌握对象和内存管理之前,请先单独使用线程。
  • 最后你可能根本不想使用Threads,ThreadPool和Task更高效,更方便。

答案 1 :(得分:0)

您的问题是您正在初始化并访问两个线程中的不同Lru_SetChanFreq个实例。您应该只初始化一个,将其分配给类字段,然后从另一个线程访问同一个实例。以下是您的代码的精简版本:

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();
    }
}

更新:我编辑了我的代码以引入正确的线程同步(以替换OP的while (LruListenThread.IsAlive)Thread.Sleep(1))。这包括三个部分:

  1. 创建两个线程都可以访问的ManualResetEvent实例。
  2. 从线程1调用WaitOne,以使其等待。
  3. 完成初始化Set后,从线程2调用Lru_SetChanFreq,从而向线程1发出信号,告知它可以继续。