Is newly added Timer thread safe?
Is newly added Timer thread safe?
11 Jul 2014, 16:03
Imagine the following scenario. I have a cBot which waits for external signals. The signals are sent through a custom socket which uses its own thread. When the signal is received, cBot needs to do something, lets suppose that it needs to change the take profit of the current position. Because the signal is received in a thread which cTrader/cAlgo does not expect to exist, I need to pass the work to the thread where cBot "usually" runs (main cBot thread). The newly added Timer class is an ideal candidate as it may be thread safe. The actual Timer property is not an instance of the normal Timer class from System.Timers. The system Timer class is designed to be thread safe in many circumstances. Also, Timer from cAlgo does not have an AutoReset property so I need to call Timer.Stop() from within the OnTimer() to make a one shot invocation on main-cBot thread.
So the question boils down to these points:
1) can I call Timer.Start() from non-main cBot thread?
2) Can I call Timer.Start with some "zero" value for the Timer to be invoked as soon as possible?
3) Can I call safely call Timer.Stop() from within OnTimer()?
Replies
Spotware
11 Jul 2014, 16:45
RE:
Hi AlexanderRC.
1) can I call Timer.Start() from non-main cBot thread?
No, it's not thread safe
2) Can I call Timer.Start with some "zero" value for the Timer to be invoked as soon as possible?
No, it will stop timer instead, otherwise it would mean smth like infinite calls of OnTimer method. In case you want to call OnTimer as soon as possible pass interval equal to one millisecond
private void ExecuteOnTimerASAP() { Timer.Start(TimeSpan.FromMilliseconds(1)); } protected override void OnTimer() { Timer.Stop(); //your code }
3) Can I call safely call Timer.Stop() from within OnTimer()?
Yes, you can safely call Stop() in OnTimer()
@Spotware
AlexanderRC
11 Jul 2014, 21:53
No, it will stop timer instead, otherwise it would mean smth like infinite calls of OnTimer method. In case you want to call OnTimer as soon as possible pass interval equal to one millisecond
Where does the one millisecond requirement come from? If OnTimer() handler takes more time than the Timer interval, will the handler be called second time simultaneously?
Are there any solution to pass "work objects" (Open/Close/Modify position) from arbitrary thread to "main" thread?
@AlexanderRC
Spotware
14 Jul 2014, 10:21
( Updated at: 21 Dec 2023, 09:20 )
Next OnTimer invocation will be scheduled after current OnTimer invocation will be finished. Please have a look at the following example:
Are there any solution to pass "work objects" (Open/Close/Modify position) from arbitrary thread to "main" thread?
You can put code that works with API objects to actions queue and invoke actions from it in OnTimer handler. In such case actions will be invoked in main thread. Example:
using System; using System.Collections.Concurrent; using System.Linq; using System.Threading; using cAlgo.API; namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class MultiThreadexample : Robot { private readonly ConcurrentQueue<Action> _actionsQueue = new ConcurrentQueue<Action>(); protected override void OnStart() { Timer.Start(new TimeSpan(1));//start timer with minimal interval var thread = new Thread(SeparateThreadHandler); thread.Start(); } private void SeparateThreadHandler() { try { //perform some actions in separate thread: Thread.Sleep(10000); //scedule action to be invoked in main thread: _actionsQueue.Enqueue(() => { //the following code will be invoked in main thread: var position = Positions.FirstOrDefault(p => p.TradeType == TradeType.Buy); if (position != null) ModifyPosition(position, Symbol.Bid - 10 * Symbol.PipSize, position.TakeProfit); }); } catch (Exception) { //you must always catch exceptions from separate thread } } protected override void OnTimer() { Action action; while (_actionsQueue.TryDequeue(out action)) { action(); } } } }
We plan to add method BeginInvokeOnMainThread in the future. It will simplify the above example.
@Spotware
AlexanderRC
14 Jul 2014, 11:35
RE:
Next OnTimer invocation will be scheduled after current OnTimer invocation will be finished
Good to know that this behavior is by design. That may have fired back on me if it was not always the case.
I have employed similar approach with work item queue where actual work is happening in OnTimer() (and previously in tick/market data updates subscribed to all possible symbols to get into main thread as frequently as possible).
Too sad there are no immediate "jump" into the main thread. I have to wait for the next Timer tick to occur.
We plan to add method BeginInvokeOnMainThread in the future. It will simplify the above example.
It would be great if BeginInvokeOnMainThread() passes execution instantly to the main thread instead of waiting for the next Timer tick to occur.
@AlexanderRC
Spotware
14 Jul 2014, 13:00
RE: RE:
It would be great if BeginInvokeOnMainThread() passes execution instantly to the main thread instead of waiting for the next Timer tick to occur.
BeginInvokeOnMainThread method will execute action instantly if there is no any handler executing by main thread and there is no handlers in the queue. Otherwise it will be put in the queue.
@Spotware
AlexanderRC
11 Jul 2014, 16:41
RE:
AlexanderRC said:
Timer.Start(new TimeSpan(1)) seems to be instant.
@AlexanderRC