4965


C# を使っています。

二つのスレッドから一つの計算メソッドを同時に使用したいのですが、

_（スレッドA → 計算メソッド ← スレッドB）_

とする場合はやはり以下のように、計算メソッドを２つ作るしかないのでしょうか？

_（スレッドA → 計算メソッドA / スレッドB → 計算メソッドB）_


CC BY-SA 3.0
2015-01-21T05:21:42.873
4960
2015-01-21T10:38:43.993
2015-01-21T06:47:46.547
4978
7626
question
c#
C# で、 2つのスレッドから 1つのメソッドを同時に呼び出したい


メソッドを2つ作る必要はありません。  
ただしスレッド間で値が競合し得るならば lock により排他制御すべきです(※calc1)。  
※ロックすべきかどうかは計算に使う値がスレッド間で競合するかどうかによります。

[code]

    using System;
    using System.Collections.Generic;
    using System.Threading;
    
    class Program
    {
        static List<int> list = new List<int>();
    
        public static int calc1()
        {
            int xxx = 0;
            lock(list)
            {
                // list を使った計算
            }
            return xxx;
        }
    
        public static int calc2(List<int> args)
        {
            int xxx = 0;
            // args を使った計算
            return xxx;
        }
    
        static void Main(string[] args)
        {
            // list が競合するので lock する必要がある
            Thread t1 = new Thread(() => {
                Console.WriteLine(calc1());
            });
            Thread t2 = new Thread(() => {
                Console.WriteLine(calc1());
            });
            t1.Start();
            t2.Start();
            t1.Join();
            t2.Join();
    
            // 引数が競合しないので lock の必要はない
            t1 = new Thread(() => {
                List<int> list = new List<int>();
                Console.WriteLine(calc2(list));
            });
            t2 = new Thread(() => {
                List<int> list = new List<int>();
                Console.WriteLine(calc2(list));
            });
            t1.Start();
            t2.Start();
            t1.Join();
            t2.Join();
        }
    
    }
    
[/code]

スレッド間で競合しないのであれば lock の必要はありません(※calc2)。  
なお、上記の list が参照しか行われないのであれば calc1 でも排他の必要はありません。


CC BY-SA 3.0
2015-01-21T05:45:26.927
4965
2015-01-21T05:45:26.927
440
4960
answer


> 二つのスレッドから一つの計算メソッドを同時に使用したいのですが、  
>  その場合はやはり計算メソッドを２つ作るしかないのでしょうか？

いいえ。2つのスレッドから同じ計算メソッドを呼び出すことは可能です。スレッド間で変数を **共有しない** かぎり、計算処理は各スレッド上で
**独立して** 並行に実行されます。

@mattnさんが指摘するように、スレッド間で変数を共有する場合には、排他制御が別途必要になります。


CC BY-SA 3.0
2015-01-21T05:48:34.983
4967
2015-01-21T05:48:34.983
49
4960
answer


Threadの生成は、控えるべきです。  
スレッドの生成は、コストの掛かる処理で、極力控えます。

代わりにTaskまたは、Parallelを使います。

  * System.Threading.Tasks.Parallel (並列)
  * System.Threading.Tasks.Task (非同期)

これらは、スレッドプールを使用します。スレッドプールは、スレッドを再利用するため、  
スレッド生成のコストを抑えることができます。  
Threadクラスを用いて生スレッドを生成する場面は、ほとんどありません。  
長期におよびプロセスの開始から終了まで稼働し続けるような場合に限るでしょう。

lockが必要な場面は、コレクションの同期、リソースの同期です。  
Listなどのコレクションは、foreachで走査している間、不変であるべきで、lock必須ですが、  
.NET 4.5以降、非同期に対応したコレクションが追加されました。

  * System.Collections.Concurrent(名前空間)
  * System.Collections.Immutable(名前空間)

Concurrentは、複数のスレッドから同時にアクセスすることができ、lockは、不要です。  
Immutableは、不変コレクションです。  
コレクションへの要素の追加/削除は、そのインスタンスに影響を与えず、  
新しいインスタンスが生成されます。

またintやlongなど単純型を共有リソースとする場合、lockよりもSystem.Threading.Interlockedクラスの使用を検討します。


CC BY-SA 3.0
2015-01-21T10:38:43.993
4996
2015-01-21T10:38:43.993
2207
4960
answer