2

マルチスレッドの場合、リストへの追加やアイテムの追加などを行う場合、変数をロックする必要があることを知っています。そうしないと、クロススレッド例外が発生します。しかし、変数を割り当てるだけでそれらをロックする必要がありますか? スレッドが変数の古いインスタンスを取得するかどうかは気にしません。エラーを発生させたくないだけです。これが私が意味することの例です:

    public void Run()
    {
        var thread1 = new Thread(new ThreadStart(Test));
        var thread2 = new Thread(new ThreadStart(Test));
        thread1.Start();
        thread2.Start();
    }

    private static int _test;

    private void Test()
    {
        while (true)
        {
            _test += 1;
        }
    }
4

3 に答える 3

5

を割り当てているだけの場合はint、いいえ。しかし、ここではただ割り当てるだけではありません。増加しています。したがって、何らかの同期が必要です。

インクリメントするには、 Interlocked.Incrementを使用します。

Interlocked.Increment(ref _test);
于 2013-07-03T18:48:27.623 に答える
0

スレッドが古いコピーを参照している可能性があることを覚えておく必要があります。ロックすることで、参照している変数のバージョンが更新されていることを確認できます。

私が最初にコーディングを開始し、変数の最新のコピーは必要ないのではないかと考えたとき、変数は最終的に更新されると想定しているため、無限ループに陥りましたが、変数がキャッシュされている場合は更新されません。

簡単な説明付きの例を含めました。スレッドの開始方法は気にしないでください。関連性はありません

private static bool _continueLoop = true;
private static readonly object _continueLoopLock = new object();

private static void StopLoop() 
{ 
    lock(_continueLoopLock) 
        _continueLoop = false;
}

private static void ThreadALoopWillGetStales()
{
    while(_continueLoop)
    {
        //do stuff
        //this is not guaranteed to end
    }
}

private static void ThreadALoopEventuallyCorrect()
{
    while(true)
    {
        bool doContinue;

        lock(_continueLoopLock)
            doContinue = _continueLoop;

        if(!doContinue)
            break;

        //do stuff
        //this will sometimes result in a stale value
        //but will eventually be correct
    }
}

private static void ThreadALoopAlwaysCorrect()
{
    while(true)
    {
        bool doContinue;

        lock(_continueLoopLock)
           if(!_continueLoop)
            break;

        //do stuff
        //this will always be correct
    }
}

private static void ThreadALoopPossibleDeadlocked()
{
     lock(_continueLoopLock)
         while(_continueLoop)
         {
             //if you only modify "_continueLoop"
             //after Acquiring "_continueLoopLock"
             //this will cause a deadlock 
         }
}

private static void StartThreadALoop()
{
    ThreadPool.QueueUserWorkItem ((o)=>{ThreadALoopWillGetStales();});
}
private static void StartEndTheLoop()
{
    ThreadPool.QueueUserWorkItem((o)=>
    {
       //do stuff
       StopLoop();
    });
}

public static void Main(string[] args)
{
    StartThreadALoop();
    StartEndTheLoop();
}

ループを開始すると、変数の古いコピーを取得し続ける可能性があります。そのため、複数のスレッドにまたがってアクセスするときに何らかの同期が必要です。

于 2013-07-03T18:45:44.473 に答える
0

コードを実行すると答えが得られるはずです... while(true)writefor(i=1;1<1e6;i++)の代わりに、結果を画面に書き込んで実行します。

合計が 2e6 になるのではなく、1.2e6 程度になることがわかります。そうです、2e6 から抜け出したい場合はロックする必要があります。

仮説を立てるだけでなく、その後は常にテストしてアサートします。

于 2013-07-03T18:53:30.047 に答える