Thread safety

I am writing a C # Windows Form application that processes quotes from the market using an algorithm (strategy) to create orders for a brokerage firm. It seems like testing is pretty good, until I tried to create the ability to run several strategies at the same time with each strategy on my own thread. At this point, everything starts to work incorrectly. I believe that I have some classes that are not thread safe, which lead to erratic behavior. Any insight into how I can draw this in a safe thread is deeply appreciated!

The way to feed quotes into algorithms is as follows: 1) Market data events are fired from Brokers software to the client class in my ConnectionStatus software. When the Market Data event is fired, the Quote object is built from the current values ​​of these static variables, which represent Bid, ask, etc. Once the quote is built, I try to send it to each of the strategy algorithms that work. Here is the code I use for this:

foreach (StrategyAssembler assembler in StrategyAssembleList.GetStrategies()) { BackgroundWorker thread = strategyThreadPool.GetFreeThread(); if (thread != null) { thread.DoWork += new DoWorkEventHandler(assembler.NewIncomingQuote); thread.RunWorkerAsync(quote); } } 

StrategyAssembler is a class that creates an instance of the StrategyManager class, which, in turn, instantiates a strategy that contains the actual algorithms. There can be 4 or 6 different instances of StrategyAssembler, each of which has been added to the Singleton instance of StrategyAssembleList, which is a BindingList.

The incoming quote object is passed to the NewIncomingQuote method of the StrategyAssembler class. This code is as follows:

 public void NewIncomingQuote(object sender, DoWorkEventArgs e) { Quote QUOTE = e.Argument as Quote; lock (QuoteLocker) { manager.LiveQuote(QUOTE); priorQuote = QUOTE; } } 

I thought that using the lock before passing the quote to the manager.LiveQuote (Quote quote) method, all objects that use the “downstream” quote at this point will be able to use the quote in a stream safe mode, but testing shows otherwise. Is there a way that I could put each instance of StrategyAssembler in its own thread that ensures that all objects created by Strategy Assembler are thread safe and then pass the quote to StrategyAssembler? Is this way of thinking the right way to deal with this situation?

Thanks in advance for any feedback or help,

Learning1

+6
multithreading c # threadpool
source share
3 answers

Locking must be performed both when reading and writing to any shared state. Without locking while reading, the code can still read and write at the same time.

You can wrap the read and write lock in the manager.

+1
source share

If a:

1) Strategies are invoked using the LiveQuote method and can modify Quote instances.

2) Changes to Quote instances should not be shared between strategies.

You need to create a copy of the provided Quote before calling LiveQuote() and send the copy to the strategy method, not the original quote. Depending on other requirements, you may not need a lock at all.

0
source share

There are two things in your code:
1. You received a quote from one stream (AKA producer - market data feed).
2. You send the quote to another stream (consumer AKA StrategyAssembler).

At this point, there is competition in the quote, in other words, the producer stream and each consumer stream (i.e. each instance of the strategy) can change the quote you just provided. In order for you to resolve the conflict, you must do one of three things:

  • Synchronize between all threads with access to quote.
    OR
  • Make the quote unchanged (and make sure the manufacturer does not replace it).
    OR
  • Give each buyer a copy of the quote.

In your case, I suggest you use the third option, because locking is more expensive than copying a quote (I hope your quotes are not very large) ... option two is also good, but your strategy should not change the quote.

By providing each consumer with a copy of the quote that you provide so that they do not share any data, so no other thread will change the quote and you will resolve the conflict. If your strategies do not create any other flows, then you are done.

In general, you should avoid blocking, and you should try to minimize data sharing, but if you are HAVE TO exchanging data between threads, you should do it right:
For your strategies to synchronize correctly, they must synchronize the same QuoteLocker object , i.e. QuoteLocker should be visible for each thread. Even if you do it right and you synchronize your strategies (block QuoteLocker ), you may also not have threads ... you will use the overhead of context switching + locking, and your strategies will be executed sequentially for the same quote.

Update for comments: If you leave the code as is (which means that you provided a copy of the quote for each thread), then I do not understand why your other strategies will not receive this quote until the first strategy is completed ... yours the first strategy will most likely begin to work while threads are being created for other strategies. The thing is that your strategies run in a separate thread to avoid this problem ... you start a new thread so that your other strategies do not expect from each other.

This part of the code is likely to be completed before all your threads start working ...

 foreach (StrategyAssembler assembler in StrategyAssembleList.GetStrategies()) { BackgroundWorker thread = strategyThreadPool.GetFreeThread(); if (thread != null) { thread.DoWork += new DoWorkEventHandler(assembler.NewIncomingQuote); Quote copy = CopyTheQuote(quote);// make an exact copy of the quote thread.RunWorkerAsync(copy); } } 

Is your market feed a changing actual quote when creating threads? Market feeds usually provide snapshots, so if something doesn’t change your quote while creating the threads, then the design above should be great. If there is a problem with the design, then I can give you the manufacturer and several consumer designs based on the blocking queue, which is also very effective ( you can check this discussion for an idea of ​​how this works , and I can tell you how to change it for your specific example).

0
source share

All Articles