0

次のコードがあるとします (すべての適切なインポート ステートメントを想定してください)。

public class CTestClass {

    // Properties
    protected Object LockObj;
    public ConcurrentDictionary<String, String> Prop_1;
    protected System.Timers.Timer TImer_1;

    // Methods

    public CTestClass () {
        LockObj = new Object ();
        Prop_1 = new ConcurrentDictionary<String, String> ();
        Prop_1.TryAdd ("Key_1", "Value_1");
        Timer_1 = new System.Timers.Timer ();
        Timer_1.Interval = (1000 * 60); // One minute
        Timer_1.Elapsed += new ElapsedEventHandler ((s, t) => Method_2 ());
        Timer_1.Enabled = true;
    } // End CTestClass ()

    public void Method_1 () {
        // Do something that requires Prop_1 to be read
        // But *__do not__* lock Prop_1
    } // End Method_1 ()

    public void Method_2 () {
        lock (LockObj) {
            // Do something with Prop_1 *__only if__* Method_1 () is not currently executing
        }
    } // End Method_2 ()

} // End CTestClass

// Main class
public class Program {

    public static void Main (string[] Args) {
        CTestClass TC = new CTestClass ();
        ParallelEnumerable.Range (0, 10)
            .ForAll (s => {
                TC.Method_1 ();
            });
    }

}

MethodBase.GetCurrentMethod を使用できることは理解していますが、(グローバル変数を使用して煩雑な簿記を行う以外に) リフレクションなしで問題を解決することは可能ですか?

よろしくお願いいたします。

編集

(a) LockObj のスコープの誤りを修正

(b)説明としてもう少し追加します(以下の私のコメントから取得)

(実際のプロジェクトで) コードを修正し、LockObj をクラス プロパティとして配置しました。問題は、Method_2 が実際には System.Timers.Timer によって起動され、起動する準備が整ったときに Method_1 が既に実行されている可能性が高いことです。ただし、その場合は、Method_1 の実行が完了するまで待ってから Method_2 に進むことが重要です。

私が作成しようとした最小限の実用的な例では、この後者の点が明確になっていないことに同意します。MWE を編集できるかどうか見てみましょう。

コードの編集が完了しました

1 つの最終編集

私は Visual Studio 2010 と .NET 4.0 を使用しているため、私の生活をずっと楽にする async/await 機能がありません。

4

4 に答える 4

0

あなたが探している用語はスレッド同期です。.NETでこれを実現する方法はたくさんあります。
そのうちの1つ(lock)を発見しました。

一般的に、ロックオブジェクトは、それを必要とするすべてのスレッドがアクセス可能であり、スレッドがロックしようとする前に初期化される必要があります。

このlock()構文により、そのロックオブジェクトに対して一度に1つのスレッドのみが続行できるようになります。同じオブジェクトをロックしようとする他のスレッドは、ロックを取得できるまで停止します。

ロックの待機をタイムアウトまたはキャンセルすることはできません(スレッドまたはプロセスを終了する場合を除く)。

例として、次の簡単な形式を使用します。

public class ThreadSafeCounter
{
    private object _lockObject = new Object();  // Initialise once
    private int count = 0; 
    public void Increment()
    {
        lock(_lockObject) // Only one thread touches count at a time
        { 
            count++; 
        }
    } 
    public void Decrement()
    {
        lock (_lockObject) // Only one thread touches count at a time
        {
            count--; 
        }
    } 
    public int Read()
    {
        lock (_lockObject) // Only one thread touches count at a time
        {
            return count; 
        }
    }
}
于 2012-05-29T05:33:28.517 に答える
0

上で指摘したように、 .net に存在する さまざまな同期プリミティブに慣れる必要があります。
リフレクションや同時実行メソッドの分析によってこのような問題を解決するのではなく、シグナリング プリミティブを使用して、メソッドが実行中/終了していることを関心のある人に通知します。

于 2012-05-29T04:29:30.530 に答える
0

これは、読者がライターの製品を消費しないという古典的なリーダー/ライターの問題の一種の変種として見ることができます。int 変数と 3 つの Mutex の助けを借りてそれを行うことができると思います。

1 つの Mutex (mtxExecutingMeth2) が Method2 の実行を保護し、Method2 と Method1 の両方の実行をブロックします。Method1 はそれをすぐに解放する必要があります。そうしないと、Method1 の他の並列実行ができなくなるからです。しかし、これは、Method1 が実行されているときに Method2 に通知する必要があることを意味します。これは、Method1 が実行されていない場合にのみ解放される mtxThereAreMeth1 Mutex を使用して行われます。これは、別の Mutex (mtxNumMeth1) によって保護される必要がある numMeth1 の値によって制御されます。

私はそれを試していなかったので、いくつかの競合状態を導入していないことを願っています. とにかく、少なくとも従うべき方向性のアイデアを与えるはずです。

そして、これはコードです:

protected int numMeth1 = 0;
protected Mutex mtxNumMeth1 = new Mutex();
protected Mutex mtxExecutingMeth2 = new Mutex();
protected Mutex mtxThereAreMeth1 = new Mutex();


public void Method_1() 
{
    // if this is the first execution of Method1, tells Method2 that it has to wait
    mtxNumMeth1.WaitOne();
    if (numMeth1 == 0)
        mtxThereAreMeth1.WaitOne();
    numMeth1++;
    mtxNumMeth1.ReleaseMutex();
    // check if Method2 is executing and release the Mutex immediately in order to avoid 
    // blocking other Method1's
    mtxExecutingMeth2.WaitOne();
    mtxExecutingMeth2.ReleaseMutex();

    // Do something that requires Prop_1 to be read
    // But *__do not__* lock Prop_1

    // if this is the last Method1 executing, tells Method2 that it can execute
    mtxNumMeth1.WaitOne();
    numMeth1--;
    if (numMeth1 == 0)
        mtxThereAreMeth1.ReleaseMutex();
    mtxNumMeth1.ReleaseMutex();
} 

public void Method_2() 
{
    mtxThereAreMeth1.WaitOne();
    mtxExecutingMeth2.WaitOne();

    // Do something with Prop_1 *__only if__* Method_1 () is not currently executing

    mtxExecutingMeth2.ReleaseMutex();
    mtxThereAreMeth1.ReleaseMutex();
} 
于 2012-05-29T06:20:38.047 に答える