【问题标题】:new thread doesn't recognize main thread already created singleton新线程无法识别已创建单例的主线程
【发布时间】:2014-08-19 17:06:19
【问题描述】:

我不确定为什么我的新线程无法识别已创建的单例实例。在启动时,我有一个创建 COM_Component 类的 Repository 类,该类创建一个 DataSubscriber 类。下面是实例化的顺序:

  1. 创建单例存储库类。
  2. Repository 类创建 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);
        }
    }

我很感激有关如何修改此代码并使其快速运行的提示,因为我已经阅读了有关多线程龙的帖子,并且我很脆并且擅长番茄酱。 :)

谢谢! 麦卡

【问题讨论】:

    标签: c# multithreading singleton


    【解决方案1】:

    我认为你有一个简单的竞争条件:

    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。您必须决定这是否真的可行,如果可行,是否有问题。

    【讨论】:

    • 谢谢 dlf,这很有道理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多