Just a enquiry, about Invoke() in Main thread - c#

I have a property that can be modified from a method with Invoke()(from thread) and other without invoke() in the same class.
what happen if they are called in the same moment?
This is possible? Since can affect the condition in some method.
For example:
public class Test{
public bool testBool { get; set; }
public void MethodWIthInvoke(){
this.Invoke(new Action(() =>
{
if (testBool)
{
testBool = false;
}
}));
}
public void Method(){
if (testBool)
{
testBool = false;
}
}
}

I am not sure why do you need to make the code this way, anyway, since both of the methods will be called from the same thread then it will be fine. I want to suggest another way to write your code as follows:
public class Test{
public bool testBool { get; set; }
public void Method()
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
if (testBool)
{
testBool = false;
}
}));
}
else
{
if (testBool)
{
testBool = false;
}
}
}
}

Related

AKKA.Net: How to send message from supervisor to child on Actor Restart

Considering this code:
public class ParentActor : ReceiveActor
{
public ParentActor()
{
for( i = 1; i <= 5; i++)
var childActor = Context.ActorOf<ChildActor>($"Child{i}");
childActor.Tell( new LoadData(i));
}
}
public class ChildActor : ReceiveActor
{
public ChildActor()
{
Receive<LoadData>(msg =>
{
var data = SomeRiskyOverNetworkCall(msg.AccountId);
});
}
}
public class LoadData
{
public int AccountId { get; }
public LoadData(int accountId)
{
AccountId = accountId;
}
}
The child actor performs some risky operation that fails from time to time
The call is using some parameters that are passed from parent/supervisor actor after creation of the child.
How to "supervise" this scenario? I need the same LoadData (with the same parameters) message to be processed after restart.
You can use pre-restart hook with some supervisor strategy. below is a simple example of the same.
https://getakka.net/articles/actors/fault-tolerance.html#creating-a-supervisor-strategy
using System;
using System.Threading;
using Akka.Actor;
namespace AkkaConsoleSimple
{
public class Start
{
public Start()
{
}
}
public class DoSomething
{
public DoSomething(int who)
{
Who = who;
}
public int Who { get; private set; }
}
public class FailedMessage
{
public FailedMessage(object who)
{
Who = who;
}
public object Who { get; private set; }
}
public class Child : ReceiveActor
{
public Child()
{
Receive<DoSomething>(msg =>
{
Console.WriteLine($"getting message no {msg.Who}");
if (msg.Who == 10)
{
throw new StackOverflowException();
}
});
}
protected override void PreRestart(Exception cause, object message)
{
Sender.Tell(new FailedMessage(message));
Self.Tell(message);
base.PreRestart(cause, message);
}
}
public class Parent : ReceiveActor
{
public Parent()
{
Receive<Start>(greet =>
{
var child = Context.ActorOf<Child>();
for (int i = 0; i < 11; i++)
{
var msg = new DoSomething(i);
child.Tell(msg);
}
});
Receive<FailedMessage>(failed => Console.WriteLine(failed.Who));
}
protected override SupervisorStrategy SupervisorStrategy()
{
return new OneForOneStrategy(
maxNrOfRetries: 10,
withinTimeRange: TimeSpan.FromMinutes(1),
localOnlyDecider: ex =>
{
switch (ex)
{
case StackOverflowException ae:
return Directive.Restart;
default:
return Directive.Escalate;
}
});
}
}
class Program
{
static void Main(string[] args)
{
var system = ActorSystem.Create("MySystem");
var greeter = system.ActorOf<Parent>("parent");
greeter.Tell(new Start());
Console.Read();
}
}
}

Memory Leak caused by Task in ViewModel

I have the following code, it causes a memory leak.
The problem is the task, when I remove it, everything is fine and the View as well as the ViewModel are GCed. It seems like the Task is keeping a reference to UpdateTimeDate and hence the ViewModel. I tried various things, but none have worked, hoping someone has any idea or explanation why it is the case.
public class HeaderViewModel : Observable, IDisposableAsync
{
public HeaderViewModel (IDateTimeProvider dateTimeProvider)
{
TokenSource = new CancellationTokenSource();
ATask = Task.Run(
async () =>
{
while(!TokenSource.Token.IsCancellationRequested)
{
UpdateTimeData();
await Task.Delay(800);
}
IsDisposed = true;
},
TokenSource.Token);
UpdateTimeData();
void UpdateTimeData()
{
TimeText = dateTimeProvider.Now.ToString("HH:mm:ss");
DateText = dateTimeProvider.Now.ToString("dd.MM.yyyy");
}
}
public CancellationTokenSource TokenSource { get; set; }
public bool IsDisposed { get; set; }
public string TimeText
{
get => Get<string>();
set => Set(value);
}
public string DateText
{
get => Get<string>();
set => Set(value);
}
private Task ATask { get; set; }
public async Task Dispose()
{
TokenSource.Cancel();
while(!IsDisposed)
{
await Task.Delay(50);
}
TokenSource.Dispose();
ATask.Dispose();
ATask = null;
TokenSource = null;
}
}
This is the Timer based solution, it also causes a memory leak:
public class HeaderViewModel : Observable, IDisposableAsync
{
public HeaderViewModel(IDateTimeProvider dateTimeProvider)
{
DateTimeProvider = dateTimeProvider;
ATimer = new Timer(800)
{
Enabled = true
};
UpdateTimeData(this, null);
ATimer.Elapsed += UpdateTimeData;
}
public string TimeText
{
get => Get<string>();
set => Set(value);
}
public string DateText
{
get => Get<string>();
set => Set(value);
}
public bool IsDisposed { get; set; }
private IDateTimeProvider DateTimeProvider { get; }
private Timer ATimer { get; }
public async Task Dispose()
{
ATimer.Stop();
await Task.Delay(1000);
ATimer.Elapsed -= UpdateTimeData;
ATimer.Dispose();
IsDisposed = true;
}
private void UpdateTimeData(object sender, ElapsedEventArgs elapsedEventArgs)
{
TimeText = DateTimeProvider.Now.ToString("HH:mm:ss");
DateText = DateTimeProvider.Now.ToString("dd.MM.yyyy");
}
}
I found a solution. Thanks to keuleJ, he posted the comment that lead me to it. So the Task or Timer is capturing an instance of the ViewModel when you create either of them. The way to prevent it is to make a WeakReference and use that:
public class HeaderViewModel : Observable, IDisposableAsync
{
public HeaderViewModel(IDateTimeProvider dateTimeProvider)
{
DateTimeProvider = dateTimeProvider;
UpdateTimeData();
var weakReference = new WeakReference(this);
Task.Run(
async () =>
{
while(!((HeaderViewModel)weakReference.Target).IsDisposing)
{
((HeaderViewModel)weakReference.Target).UpdateTimeData();
await Task.Delay(800);
}
((HeaderViewModel)weakReference.Target).IsDisposed = true;
});
}
public bool IsDisposed { get; set; }
public string TimeText
{
get => Get<string>();
set => Set(value);
}
public string DateText
{
get => Get<string>();
set => Set(value);
}
private IDateTimeProvider DateTimeProvider { get; }
private bool IsDisposing { get; set; }
public async Task Dispose()
{
IsDisposing = true;
while(!IsDisposed)
{
await Task.Delay(50);
}
}
private void UpdateTimeData()
{
TimeText = DateTimeProvider.Now.ToString("HH:mm:ss");
DateText = DateTimeProvider.Now.ToString("dd.MM.yyyy");
}
}
Note that I also could not make a local variable out of
(HeaderViewModel)weakReference.Target
As soon as I did that some magic seems to happen and the instance would be captured again.
It appears that your Dispose task never returns which is why your object is remaining in memory. I tracked down the issue to the
await Task.Delay(1000)
if you change it per this post https://stackoverflow.com/a/24539937/3084003 it will work
await Task.Delay(1000).ConfigureAwait(false);

Cross-Thread Call using MVP WIndows Forms

I would like to use MVP Design pattern for a WinForm App but i'm facing the problem of calling a View Update from another thread.
Here's my code
MODEL
public class Model : IModel
{
public string Status { get; set; }
public async void LongOperation(IHomeView View)
{
for (int i = 0; i < 1000; i++)
{
View.StatusListView = i.ToString();
}
}
}
PRESENTER
public class HomePresenter
{
IHomeView _IView;
IModel _IModel;
Model _Model = new Model();
public HomePresenter(IHomeView IView)
{
_IView = IView;
}
public async void LaunchLongOperation()
{
await Task.Run(() => _Model.LongOperation(_IView));
}
}
INTERFACE VIEW-PRESENTER
public interface IHomeView
{
string StatusListView { get; set; }
}
INTERFACE PRESENTER-MODEL
public interface IModel
{
string Status { get; set; }
}
FORM:
public partial class frmMain : Form, IHomeView
{
HomePresenter _Presenter;
public frmMain()
{
InitializeComponent();
_Presenter = new HomePresenter(this);
}
public string StatusListView
{
get
{
return lstActivityLog.Text;
}
set
{
lstActivityLog.Items.Add(value);
}
}
private void btnAvvia_Click(object sender, EventArgs e)
{
_Presenter.launchLongOperation();
}
}
i would like to update a list view in the Main form during the long operations of the Model class.
Which is the best way to do that?
Try this code without debugging, you'll be surprised about it works!
The quick and dirty way to make it work in debugging mode as well is to add Control.CheckForIllegalCrossThreadCalls = false; into the constructor of your form.
public partial class MainForm : Form, IHomeView
{
HomePresenter _Presenter;
public MainForm()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false; //<-- add this
_Presenter = new HomePresenter(this);
}
public string StatusListView
{
get
{
return lstActivityLog.Text;
}
set
{
lstActivityLog.Items.Add(value);
}
}
private void button1_Click(object sender, EventArgs e)
{
_Presenter.LaunchLongOperation();
}
}

Why isn't the Rhino Mock expectation met?

Here is code:
public interface IAccessPoint
{
int BackHaulMaximum { get; set; }
bool BackHaulMaximumReached();
void EmailNetworkProvider();
}
public class AccessPoint : IAccessPoint
{
private IMailProvider Mailer { get; set; }
public AccessPoint(IMailProvider provider)
{
this.Mailer = provider ?? new DefaultMailProvider();
}
public int BackHaulMaximum { get; set; }
public bool BackHaulMaximumReached()
{
if (BackHaulMaximum > 80)
{
EmailNetworkProvider();
return true;
}
return false;
}
public void EmailNetworkProvider()
{
this.Mailer.SendMail();
}
}
public interface IMailProvider
{
void SendMail();
}
public class DefaultMailProvider : IMailProvider
{
public void SendMail()
{
}
}
// Here is the Test, It is not calling EmailNetworkProvider which calls SendMail()
[TestFixture]
public class Tests
{
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
var mailerMock = MockRepository.GenerateMock<IMailProvider>();
mailerMock.Expect(x => x.SendMail());
var accessPoint = new AccessPoint(mailerMock);
accessPoint.BackHaulMaximum = 81;
Assert.IsTrue(accessPoint.BackHaulMaximumReached());
mailerMock.VerifyAllExpectations();
}
}
Any improvement if you use this test?
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
var mailerMock = MockRepository.GenerateStub<IMailProvider>();
var accessPoint = new AccessPoint(mailerMock);
accessPoint.BackHaulMaximum = 81;
var actual = accessPoint.BackHaulMaximumReached();
Assert.AreEqual(true, actual);
mailerMock.AssertWasCalled(x => x.SendMail());
}
As a side-note, BackhaulMaximumReached() is kind of a bizarre design. No notification will be made unless a consumer checks whether the back haul maximum was reached, regardless of the value of BackHaulMaximum.
It is semantically confusing to comingle commands and queries in this way.

Invoke a delegate on the main thread in a tiered architecture

I have a background process that i want to regularly maintain the state of gps location. I am not clear on how to invoke a delegate on the main thread in the ui layer when the threaded method is in another class. Here is sample code. My form launches the thread on load:
public partial class MainScreen : Form
{
.
. // form stuff
.
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
Thread t = new Thread(gpsStatusManager.UpdateLocation);
t.IsBackground = true;
t.Start();
}
delegate void GpsDataParameterDelegate(GpsStatus value);
public void UpdateGpsStatus(GpsStatus value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
gpsStatus.SetGpsStatus(value);
}
}
I have a domain object class for the gps information:
public class GpsStatus
{
public void SetGpsStatus(GpsStatus gpsStatus)
{
Latitude = gpsStatus.Latitude;
Longitude = gpsStatus.Longitude;
CurrentDateTime = gpsStatus.CurrentDateTime;
NumberOfSatellites = gpsStatus.NumberOfSatellites;
TotalNumberSatellites = gpsStatus.TotalNumberSatellites;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
public DateTime CurrentDateTime { get; private set; }
public int NumberOfSatellites { get; private set; }
public int TotalNumberSatellites { get; private set; }
}
Then, my manager class where i update status in the secondary thread:
public class GpsStatusManager
{
private GpsStatus _gpsStatus;
public void UpdateLocationx()
{
while (UpdateGpsData())
{
Thread.Sleep(2000);
}
}
private bool UpdateGpsData()
{
SError error;
SGpsPosition gpsPosition;
try
{
if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1)
return false;
}
catch (Exception)
{
return false;
}
var numberOfSatellites = gpsPosition.Satellites;
var totalSatellites = gpsPosition.satellitesInfo;
var datetime = gpsPosition.Time;
var lat = gpsPosition.Latitude;
var lon = gpsPosition.Longitude;
_gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites);
//How do I invoke the delegate to send the _gpsStatus data to my main thread?
return true;
}
}
Thanks for any assistance.
Here's one way to do it, just off the top of my head:
public class GpsStatusEventArgs : EventArgs
{
public GpsStatus Status { get; private set; }
public GpsStatusEventArgs(GpsStatus status)
{
Status = status;
}
}
public class GpsStatusManager
{
...
public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated;
private void OnGpsStatusUpdated(GpsStatus gpsStatus)
{
EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated;
if (temp != null)
temp.Invoke(this, new GpsStatusEventArgs(gpsStatus));
}
}
public partial class MainScreen : Form
{
...
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated);
...
}
private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e)
{
UpdateGpsStatus(e.Status);
}
...
}
Then add this to the bottom of UpdateGpsData:
OnGpsStatusUpdated(_gpsStatus);
You should use the SynchronizationContext class.
In the UI thread (in any class), set a field (perhaps static) to SynchronizationContext.Current.
You can then call Send or Post on the saved instance to execute code on the UI thread.
Here is another approach using the ISynchronizeInvoke interface. This is the same pattern the System.Timers.Timer class uses to raise the Elapsed event.
public class GpsStatusManager
{
public ISynchronizeInvoke SynchronizingObject { get; set; }
public event EventHandler Update;
public void UpdateGpsData()
{
// Code omitted for brevity.
OnUpdate(_gpsStatus);
return true;
}
private OnUpdate(GpsStatus status)
{
if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired)
{
ThreadStart ts = () => { OnUpdate(status); };
SynchronizingObject.Invoke(ts, null);
}
else
{
if (Update != null)
{
Update(this, status);
}
}
}
public class UpdateEventArgs : EventArgs
{
public GpsStatus Status { get; set; }
}
}

Categories