簡體   English   中英

新線程無法識別主線程已創建的單例

[英]new thread doesn't recognize main thread already created singleton

我不確定為什么我的新線程無法識別已經創建的單例實例。 在啟動時,我有一個Repository類,它創建一個COM_Component類,它創建一個DataSubscriber類。 這是實例化的順序:

  1. 創建singleton Repository類。
  2. 存儲庫類創建COM_Component類。
  3. COM_Component類創建DataSubscriber類。
  4. COM_Component方法為DataSubscriber生成新線程以偵聽傳入數據。
  5. 新線程上的DataSubscriber接收數據並使用Repository.Instance()來存儲數據。

問題是,當DataSubscriber調用單例時,它不會識別它之前被調用並調用構造函數,后者繼續循環遍歷上面的所有步驟。 我認為我有單例設置,以便多個線程可以正確訪問單例。 我意識到刪除多線程會更好,但這是設置示例的方式,我想快速啟動並運行。

以下是Repository類的外觀:

public class Repository
{
    public COM_Component component;
    public String defaultProjectName = "MainDB";
    public DataSet projectRepo;
    public DataTable theProjects;
    public DataTable theTasks;

    private static Repository _instance = null;
    private static readonly object _locker = new object();

    private Repository()
    {
        InitializeRepos();
        lock (_locker)
        {
            component = new COM_Component();
            component.StartListen();
        }
    }

    public static Repository Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_locker)
                {
                    if (_instance == null)
                    {
                        _instance = new Repository();
                    }
                }
            }
            return _instance;
        }
    }

COM_Component創建DataSubscriber並啟動監聽線程:

   public COM_Component()
   {
   }

   public void StartListen()
   {
       dataSubscriber = new DataSubscriber(this);

       //Spawn a new thread for each subscriber, condense into a single threaded subscriber in the near future
       _listenThread[_numThreads] = new Thread(new ThreadStart(DataSubscriber.Listen));
       _listenThread[_numThreads].Name = "DataSubscriber";
       _listenThread[_numThreads].Start();
       _numThreads++;
   }

然后DataSubscriber的數據處理程序是OnDataReceived(),在新線程上運行。 這是對Repository.Instance的調用再次觸發構造函數:

    public void OnDataReceived(DataType msg)
    {
        var selectStatement = string.Format("TaskName = '{0}'", new string(msg.msgID.Value));
        DataRow[] rows = Repository.Instance.theTasks.Select(selectStatement);
        if (rows.Length < 1)
        {
            DataRow newRow = Repository.Instance.theTasks.NewRow();
            Guid thisGuid = new Guid(); 
            newRow["TaskGuid"] = thisGuid;
            newRow["PlanID"] = Repository.Instance.defaultProjectName;
            newRow["TaskName"] = new string(msg.msgID.Value);      
            Repository.Instance.theTasks.Rows.Add(newRow);
        }
    }

我很欣賞有關如何修改此代碼並使其快速運行的提示,因為我已經閱讀了有關多線程龍的帖子,而且我對番茄醬很脆弱。 :)

謝謝! Myca

我認為你有一個簡單的競爭條件:

1)對Repository.Instance的第一次調用調用Repository構造函數

2) Repository構造函數通過component.StartListen()啟動線程

3)其中一個線程進入OnDataReceived()在構造函數返回原始線程之前調用Repository.Instance

4)此時_instance仍為null,因為在構造函數返回之前不會發生賦值,因此代碼會創建另一個實例

也許移動這個指令:

component.StartListen();

Instance getter本身:

if (_instance == null)
{
   _instance = new Repository();
   _instance.component.StartListen();
}

請注意,這意味着如果有人在正確的時刻調用它,則可以在設置完成之前獲得_instance 你必須決定這是否真的可行,如果是的話,是否是一個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM