1

public List<List<String>> listOfListsを作成してデータで埋める複数のスレッドがあります。すべてのスレッドが完了したら、メイン スレッドlist.AddRange()の複数のスレッドからこれらすべてのリストを結合するために使用したいと思います。listOfLits

したがって、3 つのスレッドがありlistOfLists、各スレッドに 10 個の要素がある場合listOflists、メイン スレッドには 30 個の要素があります。単純に足し合わせるだけで、メインスレッド オブジェクトには、スレッドによって挿入されたすべてのデータが必要です。

staticのキーワードを使用すると、完全に機能しlistOfListsます。私がしたいのは、を取り除くことだけですstatic

ここに少し例があります。

  1. シンプルな Person オブジェクトを作成します (メイン スレッド)
  2. メインスレッドはメソッドを呼び出して 3 つのスレッドを作成します
  3. これらの各スレッドは別のメソッドを呼び出して、独自のlistOfListsデータを入力します
  4. そのメソッドの最後に、独自のスレッドlistOfListsstatic listOfLists
  5. それは私が避けたいことです。静電気があってはなりません。
  6. これらのスレッドデータをメインスレッドで利用できるようにして、メインスレッドでアプリケーションを続行したいだけです。

編集:.NET 3.5でなければなりません

Edit2: 1 つの解決策は、スレッドの開始時にパラメーターとして (メイン スレッドの) 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 
    }
}
4

3 に答える 3

1

デリゲートだけでなく、デリゲートThreadStartを使用してスレッドを作成し、単一のオブジェクト パラメーターを受け取るオーバーロードを使用することもできます。スレッドのデリゲートに渡す必要のあるすべての情報を使用して、そのオブジェクトを作成します。この場合、デリゲートは、関心のあるリストの 1 つのリストにすぎません。ParameterizedThreadStartStart()

また、ロックが広すぎて、そのようなスレッドの1つだけが何かを実行できるようになり、マルチスレッドが無効になることに注意してください。処理できるものだけを処理できるようにする必要があります (privatePetこの場合は、たとえば、i各スレッドには独自の個別のビューがあるためです。Thread.CurrentThreadは静的ですが、スレッドセーフです (それ以外の場合は無意味です) 。thisスレッドセーフではなく、共有されます。複数のスレッドが文字列フィールドから読み取られ、スレッドが 1 つも書き込まれていないため、安全です ( name readonlyas を作成することで、さらに安全にすることができます。見るだけで 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);
于 2012-09-06T21:06:32.343 に答える
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のTasksandParallelを読んでください。

于 2012-09-07T07:56:45.147 に答える
0

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.

于 2012-09-06T21:05:55.550 に答える