简体   繁体   English

新线程无法识别主线程已创建的单例

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

I am unsure why my new thread doesn't recognize the singleton instance that was already created. 我不确定为什么我的新线程无法识别已经创建的单例实例。 At startup, I have a Repository class that creates a COM_Component class, which creates a DataSubscriber class. 在启动时,我有一个Repository类,它创建一个COM_Component类,它创建一个DataSubscriber类。 Here is the order of instantiation: 这是实例化的顺序:

  1. Create singleton Repository class. 创建singleton Repository类。
  2. Repository class creates COM_Component class. 存储库类创建COM_Component类。
  3. COM_Component class creates DataSubscriber class. COM_Component类创建DataSubscriber类。
  4. COM_Component method spawns new thread for DataSubscriber to listen for incoming data. COM_Component方法为DataSubscriber生成新线程以侦听传入数据。
  5. DataSubscriber on new thread receives data and uses Repository.Instance() to store data. 新线程上的DataSubscriber接收数据并使用Repository.Instance()来存储数据。

The problem is, when DataSubscriber calls the singleton, it does not recognize it being called before and calls the constructor, which continues to loop through all the steps above repeatedly. 问题是,当DataSubscriber调用单例时,它不会识别它之前被调用并调用构造函数,后者继续循环遍历上面的所有步骤。 I thought that I had the singleton setup so that multiple threads could access the singleton correctly. 我认为我有单例设置,以便多个线程可以正确访问单例。 I realize it would be better to remove the multi-threading, but this is the way the example was setup and I'd like to get something up and running quickly. 我意识到删除多线程会更好,但这是设置示例的方式,我想快速启动并运行。

Here's how the Repository class looks: 以下是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;
        }
    }

The COM_Component creates the DataSubscriber and starts the listening thread: 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++;
   }

And then the data handler for the DataSubscriber is OnDataReceived(), operating on the new thread. 然后DataSubscriber的数据处理程序是OnDataReceived(),在新线程上运行。 It's the calls to Repository.Instance that trigger the constructor again: 这是对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);
        }
    }

I'd appreciate tips on how to modify this code and get it working quickly, as I have already read the posts about multi-threaded dragons and that I am crunchy and good with ketchup. 我很欣赏有关如何修改此代码并使其快速运行的提示,因为我已经阅读了有关多线程龙的帖子,而且我对番茄酱很脆弱。 :) :)

Thanks! 谢谢! Myca Myca

I think you have a simple race condition: 我认为你有一个简单的竞争条件:

1) The first call to Repository.Instance calls the Repository constructor 1)对Repository.Instance的第一次调用调用Repository构造函数

2) The Repository constructor kicks off threads by way of component.StartListen() 2) Repository构造函数通过component.StartListen()启动线程

3) One of those threads gets into OnDataReceived() and calls Repository.Instance before the constructor has returned on the original thread 3)其中一个线程进入OnDataReceived()在构造函数返回原始线程之前调用Repository.Instance

4) _instance is still null at this point since the assignment does not occur until after the constructor returns, so the code creates another instance 4)此时_instance仍为null,因为在构造函数返回之前不会发生赋值,因此代码会创建另一个实例

Perhaps move this instruction: 也许移动这个指令:

component.StartListen();

to the Instance getter itself: Instance getter本身:

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

Note that this means someone could get _instance before listening is done being set up if they call it at the exact right moment. 请注意,这意味着如果有人在正确的时刻调用它,则可以在设置完成之前获得_instance You'd have to decide whether that's actually possible and, if so, whether it's a problem. 你必须决定这是否真的可行,如果是的话,是否是一个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM