向List <list <string>&gt;提供数据的多个线程to mainthread;多线程</列表<字符串>

时间:2012-09-06 20:02:20

标签: c# multithreading list concurrency .net-3.5

我有多个线程创建public List<List<String>> listOfLists并用数据填充它。完成所有线程后,我想使用list.AddRange()来组合主线程listOfLits中多个线程的所有列表。

所以,如果我有三个线程并且每个线程的listOfLists有10个元素,那么主线程的listOflists将有30个元素。只需简单地添加即可,主线程必须拥有线程插入的所有数据。

如果我对static使用listOfLists关键字,则效果很好。我想做的就是摆脱static

这是一个小例子。

  1. 我创建了一个简单的Person对象(主线程)
  2. 主线程调用创建3个线程的方法
  3. 每个线程调用另一个方法来填充自己的listOfLists数据
  4. 在该方法的最后,我将线程自己listOfLists添加到static listOfLists
  5. 这就是我想要避免的。一定不能有任何静电。
  6. 我只想在主线程中提供这些线程数据,并在主线程上继续应用程序。
  7. 编辑:它必须是.NET 3.5

    Edit2:一个解决方案似乎是在启动线程时提供listOfLists(主线程)的引用作为参数。有没有其他方法可以解决这样的线程问题?


    namespace Threading
    {
        class Program
        {
            static void Main(string[] args)
            {
                Person p = new Person("mainThread");
                p.startMultiThreading();
            }                   
     }
    

    class Person
    {
        public String name;
        public List<String> privatePet;
        public List<List<String>> listOfLists = new List<List<string>>();
        public static List<List<String>> familyPets = new List<List<string>>();
    
        public Person(String n) { name = n; } //constructor
        public Person() { }
    
        public void startMultiThreading()
        {
            List<Thread> list_threads = new List<Thread>();
            for (int i = 0; i < 3; i++)
            {
                Person multiThreadPerson = new Person("multi: " + i); //create new Person
                Thread t = new Thread(multiThreadPerson.fill_List); //create new Thread
                t.Name = multiThreadPerson.name; //name the Thread with PersonName
    
                list_threads.Add(t);
                list_threads[i].Start(); //new Person is calling fill_list()
            }
    
            for (int i = 0; i < list_threads.Count; i++)
            {
                list_threads[i].Join();
            }
    
            familyPets.Add(new List<string>{"this is mainthread again"});
            foreach (List<String> list in familyPets)
            {
                list.ForEach(e => Debug.WriteLine(e));
            }
        }
    
        public void fill_List()
        {
            privatePet = new List<string>();
            lock (familyPets)
            {
                for (int i = 0; i < 20; i++)
                {
                    privatePet.Add("dog :" + Thread.CurrentThread.Name);
                    privatePet.Add("cat :" + this.name);
                    listOfLists.Add(privatePet);
                }
                familyPets.AddRange(listOfLists); //adding up all listOfLists to the mainthread listOfLists
            }//lock 
        }
    }
    

3 个答案:

答案 0 :(得分:1)

ThreadStart委托一样,您可以使用ParameterizedThreadStart委托创建线程,然后使用带有单个对象参数的重载创建Start()。您可以使用传递到线程的delgate所需的任何信息来创建该对象,在这种情况下,它只是您关注的单个列表列表。

另请注意,您的锁定范围非常宽,只能让一个此类线程执行任何操作,从而破坏多线程。您希望他们自己处理只有他们可以处理的事情(例如privatePet,以及i,因为每个线程都有自己独立的视图。Thread.CurrentThread是静态的但是线程安全的(否则会毫无意义)虽然this不是线程安全的并且是共享的,但是当零线程写入时,从字符串字段读取多个线程是安全的(你是通过制作name readonly可以让它更安全,因为你可以100%放心地通过查看那些没有写入它的代码来了解它,除非它让它变得一团糟与事物。

public void fill_List(object targetList)
{
    List<List<String>> familyPets = (List<List<String>>)targetList;
    List<List<String>> listOfLists = new List<List<String>>();//we'll use our own local one of these thanks, as it's just this thread's concern write now.
    privatePet = new List<string>();
    for (int i = 0; i < 20; i++)
    {
        privatePet.Add("dog :" + Thread.CurrentThread.Name);
        privatePet.Add("cat :" + this.name);
        listOfLists.Add(privatePet);
    }
    //note you don't need to lock until you are doing something
    //that hits on something that other threads might hit on.
    //otherwise you've just got each thread locked for their entire
    //duration and you might as well just do the whole thing
    //in one thread.
    lock (familyPets)
    {
        familyPets.AddRange(listOfLists); //adding up all listOfLists to the mainthread listOfLists
    } 
}

然后在调用方法中,设置列表并将其传递到start

list_threads[i].Start(whateverTheListIsCalled);

答案 1 :(得分:0)

我认为问题在于您使用相同的类“Person”来填充数据和加入数据。

Person p = new Person("mainThread");

不会调用fill_List()并且不使用变量privatePet和listOfLists。

如果不过多修改代码,一个简单的解决方案就是添加一个新的构造函数:

public Person(String n, List<List<String>> pRefFamilyPets) { name = n; familyPets = pRefFamilyPets; } //constructor

并覆盖此行,添加familyPets参考

Person multiThreadPerson = new Person("multi: " + i, familyPets); //create new Person

我无法遵循逻辑,但这似乎避免使用STATIC,因为你将引用传递给其他线程。

答案 2 :(得分:0)

Enumerable.Range(0, 3).AsParallel().WithDegreeOfParallelism(3).Select(n => {
    var list = new List<string>();
    list.Add(n + ": One");
    list.Add(n + ": Two");
    list.Add(n + ": Three");
    return list;
}).ToList();

或者合并名单:

Enumerable.Range(0, 3).AsParallel().WithDegreeOfParallelism(3).Select(n => {
    var list = new List<string>();
    list.Add(n + ": One");
    list.Add(n + ": Two");
    list.Add(n + ": Three");
    return list;
}).Aggregate((a, b) => a.Union(b).ToList());

在MSDN上阅读任务和并行。