I have a event which in many case fires many times but I want an event to be completed before the next event is ran.
I am trying to create a cryptocurrency trading bot. The event in question is private void CoinInformation_OnNewTradeEvent(object sender, AggregateTradeEventArgs e)
Since that single event fires multiple times, I always thought it would be executed in a synchronous fashion where when one event is running, the next event wont run until this is completed. I tried putting locks but realize that doesnt work.
private void CoinInformation_OnNewTradeEvent(object sender, AggregateTradeEventArgs e)
{
lock(myObject)
{
try
{
Decimal currentTradePrice = e.Trade.Price;
UpdateSMA(currentTradePrice);
TryBuy(currentTradePrice);
TrySell(currentTradePrice);
TryStopLoss(currentTradePrice);
}
catch
{
return;
}
}
}
Sorry seems like my TryBuy and TrySell were async and I didnt await them thus there were reentries.
Related
The application is a machine control, so it needs access to ui to show status etc. (I know, goes against the recommendation to separate UI and work code, but it is what it is, at least for now). The issue boils down to this: When one button event handler is not finished, another button needs to be clicked twice. First click gives the focus to the button, next click fires the event.
Here is the issue simplified to extreme. There are two buttons and a label. Stop button needs two clicks to stop the machine:
bool Stop = true;
private void Start_button_Click(object sender, EventArgs e)
{
RunMachine();
}
private void Stop_button_Click(object sender, EventArgs e)
{
Stop = true;
}
private void RunMachine()
{
Stop = false;
Status_label.Text = "Running";
do
{
Application.DoEvents();
Thread.Sleep(50);
}
while (!Stop);
Status_label.Text = "Stopped";
}
How can I make the button to react to the first click?
DoEvents() is bad. Don't use it.
If you have to use it (e.g. as workaround), then you are adding technical debt and likely to pay in the future, similar to your case.
A better approach is to run work inside the task and use cancellation token, but in your case the minimum modification required is this (add async modifier to a method):
while (!Stop)
{
await Task.Delay(50);
// or
await Task.Run(() => Thread.Sleep(50));
}
The UI should be responsive now.
The latter is simulating synchronous code, put it instead of Sleep, don't forget to invoke if there you have to modify UI.
Thank you! I wasn't aware of the implications of Doevents, and using async and await is just as simple. I added a counter to show myself that the toy example is doing what I think it is. To make the answer complete and to help other noobs like me that might search answers for the same issue, here is the full example again. This works as wanted (stops with one click) and doesn't leave the RunMachine() running if the main form is closed without clicking stop. (My real application has enough code in the form closing event to prevent that, but I certainly wasn't aware of the trap.)
bool Stop = true;
private async void Start_button_Click(object sender, EventArgs e)
{
await RunMachine();
}
private void Stop_button_Click(object sender, EventArgs e)
{
Stop = true;
}
internal async Task RunMachine()
{
Status_label.Text = "started";
Stop = false;
int i=0;
do
{
await Task.Delay(500);
Status_label.Text = i.ToString();
i++;
} while (!Stop);
Status_label.Text = "Stopped";
}
The problem I don't know the answer to...
So on app level I want to do something when PC wakes up from sleep, so on my class ctor I did this:
public MyClass()
{
SystemEvents.PowerModeChanged += OnPowerChange;
}
OnPowerChange method looks like this:
private async void OnPowerChange(object sender, PowerModeChangedEventArgs e)
{
Debug.WriteLine(e.Mode);
if (e.Mode == PowerModes.Resume)
//Do something
}
So this event triggers only sometimes... For example when I run my app and go to sleep, when I wake - event fires. But now, when I go to sleep for the second time, after sleep, when I wake up nothing happens... Debug.WriteLine does not show anything, so the event is never fired... What could be the problem? How can I make OnPowerChange event work always?
TL;DR: Can I make a handler that is attached to many events fire only once, even when I know all of the events will be fired?
I'm trying to listen to a collection of objects, each of which will complete a specific task and then notify the owner that it is completed. To do this I've simply looped over the collection and added an event handler to each object
foreach(var obj in collection)
{
obj.Event += GroupHandler;
}
and that works fine. However since I know the tasks will complete around the same time, and since it really doesn't matter if I queue a bit early I'd like to have a way to ensure that once GroupHandler is raised, it won't be raised again for the current execution set so I could do something like:
private void GroupHandler(object sender, EventArgs e)
{
foreach(var obj in collection)
{
obj.QueueNext();
}
}
Ideally I'd end up with something like
private void GroupHandler(object sender, EventArgs e)
{
if(GroupHandler.HasRun) return;
foreach(var obj in collection)
{
obj.QueueNext();
}
}
I know that I could use some global bool (or more likely an int to track cycles) but I don't like that as a solution. I'm looking for something a bit nicer than that.
As Gusman said in comments, you can have just one of the objects fire off the event. That way you know it executes only once per event set.
Alternatively, you could set up a Timer, a counter and a flag. Set the flag on the first event execution and then start the timer. As long as the flag is set, ignore the rest of the events. Set your counter to the number of objects you're tracking and decrement the counter as each one fires off its event. When either the timer expires or the counter reaches zero, reset the flag, reset the counter and cancel the timer. This could rapidly get complicated and may have a bunch of corner cases, so if you don't care too much about timing, then the first method is much better. Simplify as much as possible.
I ended up working with what Gusman mentioned in the comments an removed the event handlers. The real key though was finding out where to reattach them. So I ended up passing the handler function in the QueueNext call.
Code looks like this
private void GroupHandler(object sender, EventArgs e)
{
foreach(var obj in collection)
{
obj.Event -= GroupHandler;
}
foreach(var obj in collection)
{
obj.QueueNext(GroupHandler);
}
}
and QueueNext looks like
public void QueueNext(EventHandler nextHandler)
{
this.Event += nextHandler
QueueNext();
}
this way the event is only called once, and will be called for each set of execution.
After asking this question, I am wondering if it is possible to wait for an event to be fired, and then get the event data and return part of it. Sort of like this:
private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();
Please make sure whatever solution you provide returns the value directly rather than getting it from something else. I'm asking if the method above is available in some way. I know about Auto/ManuelResetEvent, but I don't know that they return the value directly like I did above.
Update: I declared an event using MyEventHandler (which contains a Message field). I have a method in another thread called ReadLine waiting for the event to fire. When the event fires the WaitForValue method (part of the event handling scene) returns the event args, which contains the message. The message is then returned by ReadLine to whatever had called it.
The accepted answer to that question I asked was what I did, but it just doesn't feel quite right. It almost feels like something could happen to the data between the ManuelResetEvent firing and the program retrieving the data and returning it.
Update: The main problem with the Auto/ManualResetEvent is that it is too vulnerable. A thread could wait for the event, and then not give enough time for anyone else to get it before changing it to something else. Is there a way to use locks or something else? Maybe using get and set statements.
If the current method is async then you can use TaskCompletionSource. Create a field that the event handler and the current method can access.
TaskCompletionSource<bool> tcs = null;
private async void Button_Click(object sender, RoutedEventArgs e)
{
tcs = new TaskCompletionSource<bool>();
await tcs.Task;
WelcomeTitle.Text = "Finished work";
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
tcs?.TrySetResult(true);
}
This example uses a form that has a textblock named WelcomeTitle and two buttons. When the first button is clicked it starts the click event but stops at the await line. When the second button is clicked the task is completed and the WelcomeTitle text is updated. If you want to timeout as well then change
await tcs.Task;
to
await Task.WhenAny(tcs.Task, Task.Delay(25000));
if (tcs.Task.IsCompleted)
WelcomeTitle.Text = "Task Completed";
else
WelcomeTitle.Text = "Task Timed Out";
You can use ManualResetEvent. Reset the event before you fire secondary thread and then use the WaitOne() method to block the current thread. You can then have secondary thread set the ManualResetEvent which would cause the main thread to continue. Something like this:
ManualResetEvent oSignalEvent = new ManualResetEvent(false);
void SecondThread(){
//DoStuff
oSignalEvent.Set();
}
void Main(){
//DoStuff
//Call second thread
System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
oSecondThread.Start();
oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
oSignalEvent.Reset();
//Do more stuff
}
A very easy kind of event you can wait for is the ManualResetEvent, and even better, the ManualResetEventSlim.
They have a WaitOne() method that does exactly that. You can wait forever, or set a timeout, or a "cancellation token" which is a way for you to decide to stop waiting for the event (if you want to cancel your work, or your app is asked to exit).
You fire them calling Set().
Here is the doc.
If you're happy to use the Microsoft Reactive Extensions, then this can work nicely:
public class Foo
{
public delegate void MyEventHandler(object source, MessageEventArgs args);
public event MyEventHandler _event;
public string ReadLine()
{
return Observable
.FromEventPattern<MyEventHandler, MessageEventArgs>(
h => this._event += h,
h => this._event -= h)
.Select(ep => ep.EventArgs.Message)
.First();
}
public void SendLine(string message)
{
_event(this, new MessageEventArgs() { Message = message });
}
}
public class MessageEventArgs : EventArgs
{
public string Message;
}
I can use it like this:
var foo = new Foo();
ThreadPoolScheduler.Instance
.Schedule(
TimeSpan.FromSeconds(5.0),
() => foo.SendLine("Bar!"));
var resp = foo.ReadLine();
Console.WriteLine(resp);
I needed to call the SendLine message on a different thread to avoid locking, but this code shows that it works as expected.
Try it : e.Handled = true; It works to prevent KeyEventArgs, for example.
I have many methods (they only run one at a time though), they all use the same RunWorkerCompleated and ProgressChanged methods but they all have different Dowork methods. Is it safe to do the following:
private void button_Process_Click(object sender, EventArgs e)
{
bgWork_Process.DoWork += Scrub_DoWork;
bgWork_Process.RunWorkerAsync();
bgWork_Process.DoWork -= Scrub_DoWork;
}
or can I hit a edge case doing this? I did not see anything on the MSDN on it saying it was not allowed and it as (so far) run fine in my program, but I wanted to check here to see if anyone has run in to trouble doing this.
What you could do to make sure that the Event Handler isn't being removed until you are done with it would be to do something similar to
Action DoWorkAction;
private void button_Process_Click(object sender, EventArgs e)
{
gbHistory.Enabled = false;
gbScrub.Enabled = false;
DoWorkAction = new Action(Scrub_DoWork);
bgWork_Process.DoWork += DoWorkAction;
bgWork_Process.RunWorkerAsync();
}
And in whatever handles your completion
private void bgWork_Process_CompletedHandler(object sender, EventArgs e)
{
bgWork_Process.DoWork -= DoWorkAction;
}
I do feel, however; that it may be better to just have separate BackGroundWorkers for all of your Actions that you need to perform instead of sharing a similar one with that or wrap in a class so you can be more clear about what you are doing.