1. ホーム
  2. c#

[解決済み] 何がメソッドをスレッドセーフにするのか?そのルールは?

2022-04-22 20:28:15

質問

あるメソッドをスレッドセーフにするための全体的なルールやガイドラインはありますか?一回限りの状況がたくさんあることは理解していますが、一般的にはどうなのでしょうか?こんなに単純なことなのでしょうか?

  1. メソッドがローカル変数にしかアクセスしない場合は、スレッドセーフです。

そうなんですか?静的メソッドにも適用されるのでしょうか?

ある答えは、@Cybisさんから提供されたものです。

各スレッドが独自のスタックを取得するため、ローカル変数をスレッド間で共有することはできません。

静的メソッドもそうなのでしょうか?

あるメソッドに参照オブジェクトが渡された場合、スレッドセーフは破られるのか?しかし、いくつかのルールを使って、メソッドがスレッドセーフであることを確認するためのガイドラインを定義できればと思いました。

スレッドセーフなメソッドを定義するルールの短いリストはありますか?もしそうなら、それは何ですか?

EDIT

ここでは、多くの良い点が指摘されています。この質問に対する本当の答えは、「スレッドの安全性を確保するための単純なルールは存在しない」だと思います。素晴らしい。しかし 一般に 受理された回答は、良い、短い要約を提供していると思います。例外は常にあります。それはそれとして。私はそれに耐えることができます。

解決方法は?

メソッド(インスタンスまたは静的)がそのメソッド内にスコープされた変数だけを参照する場合、各スレッドが独自のスタックを持つため、それはスレッドセーフです。

この例では、複数のスレッドが ThreadSafeMethod を同時に実行しても問題ありません。

public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number; // each thread will have its own variable for number.
        number = parameter1.Length;
        return number;
    }
}

これは、ローカルにスコープされた変数のみを参照する他のクラスのメソッドを呼び出す場合にも当てはまります。

public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number;
        number = this.GetLength(parameter1);
        return number;
    }

    private int GetLength(string value)
    {
        int length = value.Length;
        return length;
    }
}

もしメソッドが(オブジェクトの状態の)プロパティやフィールド(インスタンスまたは静的)にアクセスする場合は、ロックを使って、値が別のスレッドによって変更されないようにする必要があります。

public class Thing
{
    private string someValue; // all threads will read and write to this same field value

    public int NonThreadSafeMethod(string parameter1)
    {
        this.someValue = parameter1;

        int number;

        // Since access to someValue is not synchronised by the class, a separate thread
        // could have changed its value between this thread setting its value at the start 
        // of the method and this line reading its value.
        number = this.someValue.Length;
        return number;
    }
}

メソッドに渡されるパラメータが構造体でも不変でもない場合、メソッドの範囲外の別のスレッドによって変異させられる可能性があることに注意する必要があります。

適切な並行性を確保するためには、ロックを使用する必要があります。

をご覧ください。 lockステートメント C#リファレンス ReadWriterLockSlim .

ロック は、主に1つずつ機能を提供するのに便利です。

ReadWriterLockSlim は、複数のリーダと単一のライタが必要な場合に便利です。