Allow exactly one thread to transmit / not to do flows without a queue

First of all, let me explain the situation ...

I have a class that has 2 properties: DataA and DataB; no matter what it is, what matters is that each can be calculated from the other. I work in a multi-threaded environment and want DataA / DataB to be calculated when and if necessary (this is not always the case both will be available). My first thought was something like ...

public SomeDataObject DataA
{
    get
    {
        if (dataAisAvailable)
        {
            return dataA;
        }
        else
        {
            if (dataBisAvailable)
            {
                lock (dataACalcLock)
                {
                    // Don't want other threads recalculating dataA
                    if (dataAisAvailable)
                    {
                        return dataA;
                    }

                    ////////////////////////////////
                    // Calculate dataA from dataB //
                    ////////////////////////////////

                    dataAisAvailable = true;
                    return dataA;
                }
            }
            else
            {
                return null;
            }
        }
    }
}

, , DataB , , ( thread1), dataA, ... , dataA, , ... imho. , , thread1 A, , .

, ManualResetEvents, , , .

, , , . ...

: , .NET 4.0. Silverlight...

+3
4

, , Lazy<> - ...

    static SomeDataObject DefaultData;

    private Lazy<SomeDataObject> dataA = new Lazy<SomeDataObject>(() => DefaultData, LazyThreadSafetyMode.ExecutionAndPublication);
    private Lazy<SomeDataObject> dataB = new Lazy<SomeDataObject>(() => DefaultData, LazyThreadSafetyMode.ExecutionAndPublication);

    public SomeDataObject DataA
    {
        get
        {
            return dataA.Value;
        }
        set
        {
            dataA = new Lazy<SomeDataObject>(() => value, LazyThreadSafetyMode.ExecutionAndPublication);
            dataB = new Lazy<SomeDataObject>(GetDataB, LazyThreadSafetyMode.ExecutionAndPublication);
        }
    }
    public SomeDataObject DataB
    {
        get
        {
            return dataB.Value;
        }
        set
        {
            dataB = new Lazy<SomeDataObject>(() => value, LazyThreadSafetyMode.ExecutionAndPublication);
            dataA = new Lazy<SomeDataObject>(GetDataA, LazyThreadSafetyMode.ExecutionAndPublication);
        }
    }

    private SomeDataObject GetDataA()
    {
        if (DefaultData == dataB.Value)
        {
            return null;
        }

        ////////////////////////////////
        // Calculate dataA from dataB //
        // and return it.             //
        ////////////////////////////////
    }
    private SomeDataObject GetDataB()
    {
        if (DefaultData == dataA.Value)
        {
            return null;
        }

        ////////////////////////////////
        // Calculate dataA from dataB //
        // and return it.             //
        ////////////////////////////////
    }

, ReaderWriterSlimLock Silverlight, . , ( , , ), , .

+1

, ReaderWriterLockSlim ( , ).

- ( , , , , ):

private ReaderWriterLockSlim dataLock = new ReaderWriterLockSlim();

public SomeDataObject DataA
{
    get
    {
        if (dataAisAvailable)
        {
            return dataA;
        }

        dataLock.EnterReadLock();

        try
        {
            if (dataBisAvailable)
            {
                dataLock.EnterUpgradeableReadLock();

                try
                {
                    // Don't want other threads recalculating dataA
                    if (dataAisAvailable)
                    {
                        return dataA;
                    }

                    dataLock.EnterWriteLock();
                    try
                    {
                        ////////////////////////////////
                        // Calculate dataA from dataB //
                        ////////////////////////////////

                        dataAisAvailable = true;
                    }
                    finally
                    {
                        dataLock.ExitWriteLock();
                    }

                    return dataA;
                }
                finally
                {
                    dataLock.ExitUpgradeableReadLock();
                }
            }
            else
            {
                return null;
            }
        }
        finally
        {
            dataLock.EnterReadLock();
        }
    }
}

Tip/plug: try/finally, ( ), , , , - IDisposable ( ).

+2

:

if (dataAisAvailable)
        {
             //Wait for AutoResetEvent here, perhaps add a timeout and when it expires, you can return the current dataA, so threads don't wait forever. 
            return dataA;
        }
        else
        {
            if (dataBisAvailable)
            {
                lock (dataACalcLock)
                {
                    // Don't want other threads recalculating dataA
                    if (dataAisAvailable)
                    {
                        return dataA;
                    }

                    ////////////////////////////////
                    // Calculate dataA from dataB //
                    ////////////////////////////////

                    dataAisAvailable = true;
                     //Set AutoResetEvent to signalled so waiting threads can get to DataA.
                    return dataA;
                }
            }
0

, , A B, , ?

dataAisAvailable , - A. dataAisAvailable , , , , dataAisAvailable false , . , . A/B , , , false.

, , - " ", "" "", ( ).

" 1" AisAvailable false . , AisAvailable , . , . " 2" , 1, AisAvailable 1, , dataA , 1 , findAisAvailable , dataA.

2-N , dataAisAvailable A, .

Rgds,

0

All Articles