Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

C# Multi Threading & Locking

Posted on 2012-09-17
5
Medium Priority
?
455 Views
Last Modified: 2012-09-23
Hi,

I have a Security object that contains two variables of type List<Price>, called CurrentPrices and NextPrices.

The security object loops through the CurrentPrices variable doing various calculations. Whilst this is being done I plan to use the ThreadPool to populate the NextPrices with data from a database.

Once the security object has finished looping through the CurrentPrices variable I copy the data from NextPrices to CurrentPrices and then NextPrices will again populate itself with fresh data whislt the security object loops through the CurrentPrices variable.

My question is how do I make sure that NextPrices has finished running before I copy its data to CurrentPrices. Please see the code below, I have stripped out some of the code to make it easier to follow as its not written to well as you can see!

Any help would be great,
Thanks,
M


public class Security
        {
            private delegate void delMultiThreadTP(Object Obj);
            private delMultiThreadTP delMultiTP;
            private int _LookBack;
            private AccessDataBank _Database;
            private ManualResetEvent _donePrice;
            private ManualResetEvent _doneFXPair;
            private DateTime _dtStart, _dtEnd;                        
            private SecurityTimeFrame[] _SecTP;
            private List<Price> _PricesNext = new List<Price>();
            private List<Price> Prices = new List<Price>();
            private string _Name;
            public string Signal{get;set;}

            private void RunTimePeriod(Object Obj)
            {
                ManualResetEvent[] doneTP = new ManualResetEvent[_SecTP.Length];

                // run through all the time periods
                for (int i = 0; i <= _SecTP.Length; i++)
                {
                    doneTP[i] = new ManualResetEvent(false);
                    _SecTP[i].RunTimePeriodSetup(doneTP[i]);
                    ThreadPool.QueueUserWorkItem(_SecTP[i].RunIndicatorDelegate, Prices);
                }

                WaitHandle.WaitAll(doneTP);

                // remove price oldest price element
                Prices.RemoveAt(0);
                
                // maybe i should be using an event here?
                if (CopyNextPriceList() == true)
                {
                    // need to copy prices over & then get next batch of prices
                    CopyPricesOver();
                   // start a new thread and repopulate _PricesNext using the GetPrices method below
                }

                _doneFXPair.Set();
            }

            private Boolean CopyNextPriceList()
            {
                Boolean Copy = false;
                if (Prices.Count < _LookBack)
                    Copy = true;                
                return Copy;
            }

            private void CopyPricesOver()
            {
                // Guessing I need to have some lock here??
                Prices.Clear();
                Prices.AddRange(_PricesNext.ToArray());
                _PricesNext.Clear();
            }

            private void GetPrices()
            {
                  _PricesNext = _Database.PriceData(_Name, _dtStart, _dtEnd);
            }
        }

Open in new window


        public class Price
        {
            public DateTime dtDTime;
            public double BidOpen, BidHigh, BidLow, BidClose;
            public double AskOpen, AskHigh, AskLow, AskClose;
            public double MidOpen, MidHigh, MidLow, MidClose;
        }

Open in new window

0
Comment
Question by:mcs26
5 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 38407546
Unless I am completely overlooking something, it appears that your code will wait before the other code is run.

You are queuing items to the ThreadPool in line 25, but once you break out of the loop, the very next instruction is to wait. The call to copy (the method in which you have a note about locking) does not come until a few lines later.

Is your code not functioning as you expect?
0
 
LVL 13

Expert Comment

by:Naman Goel
ID: 38408307
Yes, anyways you are setting your value after that so it should work. Let me give some time I will write the logic for your requirement.
0
 
LVL 9

Expert Comment

by:Orcbighter
ID: 38408944
Yes, I agree. Your code waits for all threads to complete. You then remove the first element from the Prices list (is this a debug thing? I don't quite see the point of that line) before copying the nextPrice list into the currentPrice list.

So your question is really answered by your code. You are already ensuring that you don't copy the NextPrices list into the currentPrices list before processing.

Is there a reason you process prices in a list? I mean do you do some kind of cumulative or averaging functionality on the list as a whole? If so, what determines the number of entries in the list that you populate from the database?
0
 

Author Comment

by:mcs26
ID: 38411053
Hi,

Thanks for the replies. Firstly apologies for the code I posted (apart from being a mess) it is not complete and has probably not helped.

I thought by having two variables of type MannualResetEvent[], for example doneTP & doneSomethingElse & the line WaitHandle.WaitAll(doneTP) that the waithandle would only wait for all the doneTP to be set and carry on with the rest of the code - whilst the the thread assoicted with doneSomethingElse continues to pull data. Is my understanding completely wrong?

Cheers,
M
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 2000 total points
ID: 38411761
It seems to me that your original question, "how do I make sure that NextPrices has finished running before I copy its data to CurrentPrices" would be satisfied by putting the NextPrices logic on its own thread and waiting on that thread to finish before waiting on the other threads:

public class Security
{
    private delegate void delMultiThreadTP(Object Obj);
    private delMultiThreadTP delMultiTP;
    private int _LookBack;
    private AccessDataBank _Database;
    private ManualResetEvent _donePrice;
    private ManualResetEvent _doneFXPair;
    private DateTime _dtStart, _dtEnd;                        
    private SecurityTimeFrame[] _SecTP;
    private List<Price> _PricesNext = new List<Price>();
    private List<Price> Prices = new List<Price>();
    private string _Name;
    public string Signal{get;set;}
    
    private ManualResetEvent _nextPriceMRE = new ManualResetEvent(false);

    private void RunTimePeriod(Object Obj)
    {
        ManualResetEvent[] doneTP = new ManualResetEvent[_SecTP.Length];
        
        ThreadPool.QueueUserWorkItem(GetPrices);

        // run through all the time periods
        for (int i = 0; i <= _SecTP.Length; i++)
        {
            doneTP[i] = new ManualResetEvent(false);
            _SecTP[i].RunTimePeriodSetup(doneTP[i]);
            ThreadPool.QueueUserWorkItem(_SecTP[i].RunIndicatorDelegate, Prices);
        }

        WaitHandle.WaitAny(new WaitHandle[] { this._nextPriceMRE });
        WaitHandle.WaitAll(doneTP);

        // remove price oldest price element
        Prices.RemoveAt(0);

        // maybe i should be using an event here?
        if (CopyNextPriceList() == true)
        {
            // need to copy prices over & then get next batch of prices
            CopyPricesOver();
           // start a new thread and repopulate _PricesNext using the GetPrices method below
        }

        _doneFXPair.Set();
    }

    private Boolean CopyNextPriceList()
    {
        Boolean Copy = false;
        if (Prices.Count < _LookBack)
            Copy = true;                
        return Copy;
    }

    private void CopyPricesOver()
    {
        // Guessing I need to have some lock here??
        Prices.Clear();
        Prices.AddRange(_PricesNext.ToArray());
        _PricesNext.Clear();
    }

    private void GetPrices()
    {
        _PricesNext = _Database.PriceData(_Name, _dtStart, _dtEnd);
        this._nextPriceMRE.Set();
    }
}

Open in new window


I added a new MRE to the above (simply because I don't know what all of the existing ones are for). In the above I am starting the GetPrices method prior to doing the logic you originally had. This allows the GetPrices to run while the other logic runs. Then, as you were already doing, the security objects are queued up to be threaded. Once that loop terminates, you wait on the GetPrices thread to return. Once it returns, you wait on the security object threads to return. Then the rest of the logic should see only updated prices in _PricesNext since we waited for that thread to finish before proceeding.

Do note:  this code is *highly* dependent on the current code you posted. If you are exposing _PricesNext or Prices to the outside world (via properties or methods), then this code would need to be reworked. The reason is that you would have instance members being operated on by a thread, and this can lead to race conditions and data corruption (probably even other issues) if not accounted for properly.

Also, you need to test the above. I cannot claim to be a threading expert. (I wouldn't even be surprised if someone popped in with, "WTF are you doing!!".) I believe the above is sound, but as I don't have your full code to test with, I can only claim.
0

Featured Post

Restore individual SQL databases with ease

Veeam Explorer for Microsoft SQL Server delivers an easy-to-use, wizard-driven interface for restoring your databases from a backup. No expert SQL background required. Web interface provides a complete view of all available SQL databases to simplify the recovery of lost database

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question