Reputation: 13553
I have multiple threads that create a public List<List<String>> listOfLists
and fill it with data. After all threads are done, I would like to use list.AddRange()
to combine all those lists from the multiple threads in the listOfLits
of the main thread.
So, if I have three threads and listOfLists
of each thread has 10 elements, then listOflists
of the main thread would have 30 elements. Just simple add 'em up and the mainthread object has to have all the data inserted by the threads.
It works perfectly if I use the static
keyword for the listOfLists
. All I want to do is to get rid of static
.
Here is a little example.
listOfLists
with datalistOfLists
to the static listOfLists
Edit: it has to be .NET 3.5
Edit2: One solution seems to be to provide the reference of listOfLists (of main thread) as parameter when starting the threads. Are there any other ways to solve such a threadingproblem?
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
}
}
Upvotes: 1
Views: 2197
Reputation: 2061
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();
Or to combine the lists:
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());
Read up on Tasks and Parallel on MSDN.
Upvotes: 0
Reputation: 113272
As well as the ThreadStart
delegate, you can create a thread using the ParameterizedThreadStart
delegate, and then Start()
with an overload that takes a single object parameter. You make that object with whatever information you need to pass into the thread's delgate, which in this case is just the single list of lists that you are concerned with.
Note also that your locking was so wide as to only let one such thread to do anything, defeating the multi-threading. You want them to work on their own with things only they can deal with (privatePet
in this case for example, and also i
because each thread has their own separate views of them. Thread.CurrentThread
is static but thread-safe (it would be pointless otherwise) and while this
is not thread-safe and is shared, to have several threads read from a string field while zero threads are writing to it, is safe (you could make it safer still by making name
readonly
as then you could know with 100% confidence just by looking at that code that nothing was going to write to it, unless it went out of its way to mess with things.
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
}
}
Then in the calling method, you set up your list and pass it in the start
:
list_threads[i].Start(whateverTheListIsCalled);
Upvotes: 1
Reputation: 252
I think that the problem is that you are using the same class "Person" for both filling data and joining data.
Person p = new Person("mainThread");
doesnt ever calls fill_List() and doesnt use the variables privatePet and listOfLists.
Without modifying your code too much, one easy solution would be to add a new constructor:
public Person(String n, List<List<String>> pRefFamilyPets) { name = n; familyPets = pRefFamilyPets; } //constructor
and overwrite this line, adding the familyPets reference
Person multiThreadPerson = new Person("multi: " + i, familyPets); //create new Person
I couldnt follow the logic but this seems to avoid the use of STATIC, since youre passing the reference around to the other threads.
Upvotes: 0