我正在尝试第一次对应用程序进行线程化。该应用程序使用一个大型数据集,该数据集被分成可管理的块,这些块存储在磁盘上,因此整个数据集永远不必一次全部驻留在内存中。取而代之的是,数据的子集可以根据需要逐个加载。这些块先前是在主线程中一个接一个地加载的。当然,这将有效地暂停所有GUI和其他操作,直到数据完全加载为止。

因此,我决定研究线程,并在应用程序继续正常运行的同时进行加载。通过执行以下伪代码,我能够获得使用ThreadPool的基本概念:

public class MyApp
{
    List<int> listOfIndiciesToBeLoaded; //This list gets updated based on user input
    Dictionary<int,Stuff> loadedStuff = new Dictionary<int,Stuff>();

    //The main thread queues items to be loaded by the ThreadPool
    void QueueUpLoads()
    {
        foreach(int index in listOfIndiciesToBeLoaded)
        {
            if(!loadedStuff.ContainsKey(index))
                loadedStuff.Add(index,new Stuff());

            LoadInfo loadInfo = new LoadInfo(index);
            ThreadPool.QueueUserWorkItem(LoadStuff, loadInfo);
        }
    }

    //LoadStuff is called from the worker threads
    public void LoadStuff(System.Object loadInfoObject)
    {
        LoadInfo loadInfo = loadInfoObject as LoadInfo;
        int index = loadInfo.index;

        int[] loadedValues = LoadValuesAtIndex(index); /* here I do my loading and ...*/

        //Then I put the loaded data in the corresponding entry in the dictionary
        loadedStuff[index].values = loadedValues;
        //Now it is accessible from the main thread and it is flagged as loaded
        loadedStuff[index].loaded = true;
    }
}

public class Stuff
{
    //As an example lets say the data being loaded is an array of ints
    int[] values;
    bool loaded = false;
}

//a class derived from System.Object to be passed via ThreadPool.QueueUserWorkItem
public class LoadInfo : System.Object
{
    public int index;

    public LoadInfo(int index)
    {
        this.index = index;
    }
}

与过去几天尝试学习这些东西时遇到的非常复杂的示例相比,这是非常原始的。当然,它可以同时加载数据并将其填充到可从主线程访问的字典中,但这也给我带来了一个关键问题。我需要在加载项目以及加载哪个项目时通知主线程,以便可以处理和显示新数据。理想情况下,我想让每个完成的加载在主线程上调用一个函数,并为其提供索引和新加载的数据作为参数。我知道我不能只从同时运行的多个其他线程中调用主线程上的函数。它们必须以某种方式排队,以便主线程在不执行其他操作时运行它们。但是,这是我目前对线程通信的了解下降的地方。

我已经阅读了一些深入的说明,其中介绍了在使用Windows Forms时如何使用Control.Invoke(delegate)设置事件和委托(delegate)。但是我不使用Windows窗体,也无法应用这些想法。我想我需要一种不依赖Control类的更通用的方法。如果您确实有回应,请进行详细说明,并在我的伪代码中使用一些命名。这样,我将更容易理解。线程似乎是一个很深的话题,而我只是想掌握一些基础知识。另外,请随时就我如何使问题更清晰明确提出建议。

最佳答案

如果您不使用带有某种调度程序或GUI线程(例如WPF或WinForms)的GUI框架,则必须手动执行此操作。

一种实现方法是使用SynchronizationContext。
管理起来有些棘手,但是有几篇文章介绍了它的工作方式以及如何制作自己的文章:

http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I
http://www.codeproject.com/Articles/32113/Understanding-SynchronizationContext-Part-II

但是,我也将考虑使用单个“DictionaryChanged” bool 值,该 bool 值由“主线程”(在空闲时)定期检查,以指示字典已更改。然后可以在主线程上重置该标志,以指示已处理该标志。请记住,您需要在此处进行一些锁定。

您还可以使用线程安全队列对消息进行排队,如果简单变量不足,则该线程安全队列由后台线程编写并从主线程读取。本质上,这就是大多数调度程序实现实际上是在后台执行的操作。

关于c# - 线程池-如何从工作线程中调用主线程中的方法(带有参数),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22681576/

10-09 00:46