How to create a timer callback that can edit its state object? - c#

I have a System.Threading.Timer that receives some data each second, and I want its callback to put the received data into an object, which should be returned to client code. I tried to implement that using C#'s reference types mechanism. Here's the current callback:
private void Receive(object? obj) {
var data = GetData();
obj = (object)data; // Does nothing
}
And here's the method that starts the timer (timer is a field):
public void Start(Image image) {
timer = new Timer(
Receive,
image,
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1)
);
}
Expected behavior: each second the data (which is image data) is received and put to the image, the reference to which is specified in parameter image.
Actual behavior: when I defined a variable of type Image, passed it to the Start method and checked its value (using the Visual Studio debugger) after 5 seconds, it was the empty Bitmap I assigned to it at the very start.
I have also checked that the data (containing non-empty image) is sent properly.
Can anybody tell me what's the issue, or, alternatively, suggest a different way to change the "state" object in a timer callback?

obj = (object)data; only sets the data locally in the Receive method. You could fix it by creating a wrapper object
public class ImageData
{
public Image Image { get; set; }
}
Then create a static instance of it that can be accessed from where you need it
public static readonly ImageData Data = new ImageData();
Depending on where you must access the images it can also an instance member and be private; however, it must always be the same instance that you used to start the timer.
Then start like this
public void Start() {
timer = new Timer(
Receive,
Data,
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1)
);
}
And receive
private void Receive(object? obj) {
var data = (ImageData)obj;
data.Image = GetData();
}
Now, you can access the new images through the static Data.Image property.
Alternatively, you could "consume" the image (i.e., display or whatever you are doing with it) directly in the Receive callback and ignore the obj parameter. However, I do not have enough context information (where do the different code pieces reside and in which thread are they executed, etc.).
Update
The Image will be null in ImageData first, until the Receiver callback is called for the first time.
If you want an image at the very start, you can do several things.
Start the timer with the first time argument as 0 (this is the time it waits until firing the first time).
Call the callback directly in Start: Receive(Data).
Assign an image with Data.Image = GetData();.
Initialize the image in ImageData with a dummy image (maybe some kind of wait image).
Update 2
Apparently you are creating a library. I assume the library will pull images regularly and make them available to a consumer.
I suggest exposing an event in the library any consumer can subscribe to to receive images.
In the library we declare event arguments as
public class UpdateImageEventArgs : EventArgs
{
public UpdateImageEventArgs(Image image)
{
Image = image;
}
public Image Image { get; }
}
A possible implementation of the library:
public class Library : IDisposable
{
public event EventHandler<UpdateImageEventArgs>? ImageUpdated;
private System.Threading.Timer? _timer;
public void Start()
{
_timer = new System.Threading.Timer(Receive, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
}
private void Receive(object? obj)
{
var image = GetImage();
ImageUpdated?.Invoke(this, new UpdateImageEventArgs(image));
}
private static Image GetImage()
{
// TODO: Add your implementation
throw new NotImplementedException();
}
public void Dispose()
{
if (_timer != null) {
_timer.Dispose();
_timer = null;
}
}
}
The consumer code:
public static void Test()
{
var library = new Library();
library.ImageUpdated += Library_ImageUpdated;
library.Start();
}
private static void Library_ImageUpdated(object? sender, UpdateImageEventArgs e)
{
DoSomethingWith(e.Image);
}
If you want to stop the timer, you can do so by calling library.Dispose();. This also ensures that the timer resources are disposed properly.

In the Recieve method you get an obj as input reference. Then you try to set a value to obj. This last step cannot work, since you work on the reference.
The only way it could work is, if the input reference is given as a ref, which is
private void Receive(ref object? obj) {}
Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller.

Related

Main thread coroutine using Queue<Action>

I am having a little trouble when i get some data from websockets and try to display it through coroutines.
First, I have a classA attached to an object that opens the websocket and displays the data I receive:
public class ClassA : MonoBehaviour {
...
public IEnumerator ConnectWebSocket(url)
{
// in the websocket class, start the websocket connection, which
// will return data through a callback inside the return string
WebSocketClass.WebSocketStart(url, delegate(string result)
{
// receive websocket data and call the functions that displays it
WebSocketData(result);
});
// wait for the socket connection
while (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.CONNECTING)
{
yield return 0;
}
if (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.OPEN)
{
break;
}
...
}
// function that gets websocket data and starts couroutine to display it
public void WebSocketData(string data)
{
StartCoroutine(DisplayMessage(data));
}
}
But Unity complains with the next error:
StartCoroutine_Auto can only be called
from the main thread. Constructors and
field initializers will be executed
from the loading thread when loading a
scene. Don't use this function in the
constructor or field initializers,
instead move initialization code to
the Awake or Start function.
I searched in the unity forum and found this solution:
public class ClassA : MonoBehaviour {
...
public IEnumerator ConnectWebSocket(url)
{
// in the websocket class, start the websocket connection, which
// will return data through a callback inside the return string
WebSocketClass.WebSocketStart(url, delegate(string result)
{
// receive websocket data and call the functions that displays it
WebSocketData(result);
});
// wait for the socket connection
while (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.CONNECTING)
{
yield return 0;
}
if (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.OPEN)
{
break;
}
...
}
// function that gets websocket data and starts couroutine to display it
public void WebSocketData(string data)
{
DoOnMainThread.ExecuteOnMainThread.Enqueue(() => { StartCoroutine(DisplayMessage(data)); });
}
}
// class to manage the websocket data display inside the main thread
public class DoOnMainThread : MonoBehaviour
{
public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
public virtual void Update()
{
// dispatch stuff on main thread
while (ExecuteOnMainThread.Count > 0)
{
ExecuteOnMainThread.Dequeue().Invoke();
}
}
}
And it works! the problem is that even though I wrote the two classes in the same cs file and attached to an object, when I change the scene, return to that scene, and receive any data from the websocket, the next error is displayed:
MissingReferenceException: The object
of type 'ClassA' has been destroyed
but you are still trying to access it.
Your script should either check if it
is null or you should not destroy the
object.
UnityEngine.MonoBehaviour.StartCoroutine
(IEnumerator routine) (at
C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineMonoBehaviour.cs:62)
I tried not destroying the object when a new scene is loaded, as the documentation says:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
But the error still appears.
The weird thing is that although there is an error, the data received from the websocket is displayed without any problem.
Does someone know how to avoid this problem? Any way to trigger a coroutine inside the main thread without using a second class? Or other solution to avoid this error?
Thanks!
I found the problem:
public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
It is static, so it becomes a problem when a public class is instantiated and generates another ExecuteOnMainThread.
So just deleted "static" and made it destroy and generate itself every time ClassA is created by Unity.
Now it works like a charm : )

sharing variables between thread and class

I have created an app with a class containing some data that are updated at a regular interval using a timer. This class also contains some public function to pass the data to another class. Here is how it looks:
private void OnTimer(object sender, ElapsedEventArgs status)
{
GetNewData();
}
public void GetData(ref List<double> data, int index)
{
if (index < m_data.Length)
{
data = new List<double>(m_data[index]);
}
else
{
data = new List<double>();
}
}
At the moment, I don't have any protection to assure that the function GetData is not accessing the data while it is been modified.
Could you point me to the best way of protecting my shared data?
You can put a lock on your code. Each thread will wait on your lock statement and then will go inside your new data creation:
private void OnTimer(object sender, ElapsedEventArgs status)
{
GetNewData();
}
object lockCheck = new object();
public void GetData(ref List<double> data, int index)
{
lock(lockCheck)
{
if (index < m_data.Length)
{
data = new List<double>(m_data[index]);
}
else
{
data = new List<double>();
}
}
}
You're not too specific about how you're updating your data. If your GetNewData method completely replaces the m_data member, then there's no need for a lock at all. Consider this:
// this is the shared data
SomeDataType m_data;
// Method that reads the data
public void GetData(ref List<double> data, int index)
{
// get a reference to the existing data
var localData = m_data;
// only work with the localData reference here
}
private void OnTimer(object sender, ElapsedEventArgs status)
{
GetNewData();
}
Now, make your GetNewData method load the data using a local variable. Once it's all loaded, replace the m_data reference:
private void GetNewData()
{
var localData = /* create the data here */
// replace the reference
m_data = localData;
}
Using this technique, there's no way for the get method and the timer to interfere with each other. If GetNewData is called while the getter is running, there's no problem because the getter is working with a local reference.
The only potential problem is that if the getter is called while GetNewData is running, then the value returned will be from the old list. That is, potentially stale data. Whether this is a problem is really a matter for you to decide.
There are collections specifically designed to be used for multiple threads to provide data to each other. You can use a BlockingCollection, which is a wrapper for a ConcurrentQueue to allow your timer to generate data, add it to the queue, and then have code elsewhere reading from that queue and processing the results. The BlockingCollection will then be responsible for all synchronization between threads.

Is it possible for instance to destroy/delete self?

NOTE: I'm interested in C#,Java and C++ most, but as this is the more academic question any language will do.
I know that this problem is solvable from outside, by using appropriate methods of given languages (calling free, Dispose, or by removing all references to instance).
My idea is that I create an instance, and in the constructor , I start the private timer. When the timer ends it will call some instance method and destroy the variable.
I think that in C# it should be possible to call Dispose on self, when the IDisposable is implemented, but this would not destroy the instace.
In C++ I could call the destructor, but that would lead to the memory leak, plus it is really bad practice.
In Java I have no clue, assigning to this it's not possible as it is final field.
So is there any way for instance, to destroy self?
Your question is very interesting, and I don't know of any other way to do so in C# but to force from the inside of the instance its destruction from the outside. So this is what I came up with to check if it is possible.
You can create the class Foo, which has event that is fired when the specific interval of the timer elapses. The class that is registered to that event (Bar) within event de-registers the event and sets the reference of the instance to null. This is how I would do it, tested and it works.
public class Foo
{
public delegate void SelfDestroyer(object sender, EventArgs ea);
public event SelfDestroyer DestroyMe;
Timer t;
public Foo()
{
t = new Timer();
t.Interval = 2000;
t.Tick += t_Tick;
t.Start();
}
void t_Tick(object sender, EventArgs e)
{
OnDestroyMe();
}
public void OnDestroyMe()
{
SelfDestroyer temp = DestroyMe;
if (temp != null)
{
temp(this, new EventArgs());
}
}
}
public class Bar
{
Foo foo;
public Bar()
{
foo = new Foo();
foo.DestroyMe += foo_DestroyMe;
}
void foo_DestroyMe(object sender, EventArgs ea)
{
foo.DestroyMe -= foo_DestroyMe;
foo = null;
}
}
And in order to test this, you can set up a button click within a Form, something like this, and check it in the debugger:
Bar bar = null;
private void button2_Click(object sender, EventArgs e)
{
if(bar==null)
bar = new Bar();
}
So next time when you click the button, you will be able to see that Bar instance still exists but the Foo instance within it is null although it has been created within the Bar's constructor.
C++: If an object was allocated dynamically, it can delete its this pointer in its own function, provided the this pointer is never used again after that point.
No, there is no way to achieve what you are trying to do in C#.
If you consider an example :
public class Kamikadze {
......
private void TimerTick(..)
{
....
if(itsTime) {
DestroyMe();
}
}
.....
}
var kamikadze = new Kamikadze ();
after a while DestroyMe() will be called that cleans internal data.
But the reference kamikadze (pointer if you wish) is still valid and points to that memory location, so GC will not do anything, will not collect it, and instance of Kamikadze will remain in memory.
For C++ take a look at this:
http://www.parashift.com/c++-faq/delete-this.html
.
The closest thing in C# that I can think of:
On creation, every object stores a reference to itself in the GC root, e.g. by putting the reference into a class static list. Outside of the class, nobody is allowed to store (strong) references to the object. Everybody uses a WeakReference and checks if the Target is still IsAlive before touching the object. That way, the only thing that is keeping the object alive is the static reference.
When the object decides to kill itself, it simply removes the reference from the list. Sooner or later, the GC collects the object. Or, if you are really impatient, call GC.Collect() (ouch!).
But I really really would not recommend this solution!
It's much better put some flag into the class/object to signal whether it's still alive and make everybody check this flag before using the object. This can be combined with the IDisposable solution.
In C++, instances committing suicide are an integral part of the Finite State Machine Pattern:
//Context class contains a pointer to a State object.
void BattleshipGame::SetGameState(IState* state) {
game_state = state;
}
void BattleshipGame::Loss() {
game_state->Loss(this);
}
void BattleshipGame::Idle() {
game_state->Idle(this);
}
void BattleshipGame::FlyBy() {
game_state->FlyBy(this);
}
void BattleshipGame::Attack() {
game_state->Attack(this);
}
void BattleshipGame::Win() {
game_state->Win(this);
}
void BattleshipGame::Load() {
game_state->Loading(this);
}
//State base class contains methods for switching to every state.
class IState {
public:
virtual void Loading(BattleshipGame* context);
virtual void Idle(BattleshipGame* context);
virtual void FlyBy(BattleshipGame* context);
virtual void Attack(BattleshipGame* context);
virtual void Win(BattleshipGame* context);
virtual void Loss(BattleshipGame* context);
protected:
private:
};
//Implementations in the State base class are defined, but empty.
//Derived States only call what they need:
void StateIdle::Loss(BattleshipGame* context) {
//context->SetGameState(new StateLoss());
context->SetGameState(new StateLoss(context));
delete this;
}
void StateIdle::Idle(BattleshipGame* context) {
context->SetGameState(new StateIdle());
delete this;
}
void StateIdle::FlyBy(BattleshipGame* context) {
context->SetGameState(new StateFlyBy());
delete this;
}
void StateIdle::Win(BattleshipGame* context) {
context->SetGameState(new StateWin());
delete this;
}
//Similar design for all other states...
In C#, you're right you can implement IDisposable but the trick is instead of calling Dispose method make use of the using statement.
class Program
{
static void Main(string[] args)
{
using (MyClass obj = new MyClass())
{
obj.SayHello();
}
// obj.SayHello(); // Error: The name 'obj' does not exist in the current context
}
}
class MyClass : IDisposable
{
public void SayHello()
{
Console.WriteLine("Hello");
}
public void Dispose()
{
// Do something (e.g: close some open connection, etc)
}
}
For Reference: microsoft-docs/using-statement
I recommend using NFTLKEY. You can easily get it from the Nuget package. Best of all, it's open source: github project
Easier to understand than the examples here

Access object from Event Handler

I am using an external class to open up a connection to a remote application. This class receives the data from the remote application which is handled via a handler.
To this handler I have added several checks to parse the data in separate methods. However I am now stuck at the point where I need to access the object again which triggered the event to call a method on it. I am sure this is a pretty basic question but I am just starting with OOP.
public static void Main(string[] args) {
IBattleNET b = new BattlEyeClient(loginCredentials);
b.MessageReceivedEvent += HandleMessage;
b.Connect();
}
private static void HandleMessage(BattlEyeMessageEventArgs args) {
//call a method to analyze data parse
PlayerList(args.Message);
}
private static void parsePlayerList(string playerList) {
// At this point I need to access the object b again to to call a method
}
Modify the handler to pass over the object:
b.MessageRecievedEvent += (e) => HandleMessage(b, e);
....
private static void HandleMessage(IBattleNet b, BattleMessageEventArgs args) {
....
The lambda expression stores the args as 'e', then calls HandleMessage by passing it both the object and 'e'.
The convention Pickles presented is better practice, however, if you have access to and can change the event itself inside of IBattleNET.
Typically events use delegates that have two parameters in their signature. An object "source" parameter to represent the sender and an "args" parameter to represent the event args.
If you have access to the MessageReceivedEvent you should change the delegate to include an "object" parameter to represent the sender. Then your HandleMessage method would look like this:
private static void HandleMessage(object sender, BatlEyeMessageEventArgs args)
{
var battleNet = sender as IBattleNet;
if (battleNet == null)
return;
battleNet.Foo();
PlayerList(args.Message);
}
Since your incoming method is static, you are presented with some challenges, particularly what happens when multiple messages arrive in a very close period of time? If you store the information that you want to reuse later, it could easily be overwritten by the next message that is received.
In cases like this, I generally create a new class that is responsible for the parsing and processing of the incoming message and, in the event handler, create a new instance of that class passing the event arguments to the constructor.
From that point forward, all processing of the message occurs in the class instance.
For example, you could have a class like this that stores the message, validates it, and then later performs some parsing on it::
public class PlayerListEvent
{
private string m_sMessage;
public PlayerListEvent(String sMessage)
{
m_sMessage = sMessage;
}
public Boolean MessageIsValid()
{
// Validate the incoming message
return true;
}
public void ParseMessage() {
// Perform the message parsing
}
}
You could store all incoming messages in a list (or class or some other storage mechanism) so that they can be processed as needed:
private static System.Collections.Generic.List<PlayerListEvent> m_cReceivedMessages = new System.Collections.Generic.List<PlayerListEvent>();
Then, when your message arrives, you can create a new instance of the class and, if it's valid, add it to the queue for processing later (you could do just about anything here including firing a background worker process to handle the incoming message, etc):
private static void HandleMessage(BattlEyeMessageEventArgs args) {
//call a method to analyze data parse
var oPlayerListEvent = new PlayerListEvent(args.Message);
if (oPlayerListEvent.MessageIsValid()) {
lock (m_cReceivedMessages) {
m_cReceivedMessages.Add(oPlayerListEvent);
}
}
}

Thread contained inside class

I'm writing a simple Windows forms application to get me into the swing of things with Threads. So far what I have is working, but what I would like to do is contain it all in a seperate class rather than directly in my forms code.
I have a background thread that starts and retrieves data from a database. I then display that data in to a listbox.
private delegate void UpdateListValues(List<ListBoxItem> itemList);
private void form_main_Shown(object sender, EventArgs e)
{
// Set the loading text.
list_selection.Items.Add(ListHelpers.LoadingItem());
// Start the data access on a seperate thread.
Thread worker = new Thread(GetInvoicingData);
worker.IsBackground = true;
worker.Start();
}
private void GetInvoicingData()
{
// Query database
List<ListBoxItem> values = DAC.GetInvoicingAccounts();
// Display results
BeginInvoke(new UpdateListValues(DisplayList), new object[] { values });
}
private void DisplayList(List<ListBoxItem> itemList)
{
// Display each result
list_selection.Items.Clear();
for (int i = 0; i < itemList.Count; i++)
{
list_selection.Items.Add(itemList[i]);
}
}
The problem is that in the DisplayList method, I won't be able to access the list box (list_selection) because it's part of the form class. Does anyone have any suggestions on how I can do this.
Also, I'm new to threading so feel free to tell me I'm doing it absolutely wrong. I just used the example from http://www.codeproject.com/Articles/23517/How-to-Properly-Handle-Cross-thread-Events-and-Upd to get me to where I am now.
Thanks
How about something like this:
// Added the form's class declaration to highlight separation of thread code into a separate class, but may not be exactly the same as yours depending on naming
public class Form1 : Form
{
private readonly DataRetriever _dataRetriever;
private void form_main_Shown(object sender, EventArgs e)
{
// Set the loading text.
list_selection.Items.Add(ListHelpers.LoadingItem());
// Create the DataRetriever, and provide it with a delegate to DisplayList for returning data
_dataRetriever = new DataRetriever(DisplayList);
// Start retrieving data on a separate thread...
_dataRetriever.GetData();
}
private void DisplayList(List<ListBoxItem> itemList)
{
if (InvokeRequired)
{
// Ensure the update occurs on the UI thread
Invoke((Action)(() => DisplayList(itemList)));
return;
}
// Display each result
list_selection.Items.Clear();
foreach (var item in itemList)
{
list_selection.Items.Add(item);
}
}
}
// Separate class to hold thread code
public class DataRetriever
{
public delegate void UpdateCallbackDelegate(List<ListBoxItem> itemList);
private readonly UpdateCallbackDelegate _updateCallback;
public DataRetriever(UpdateCallbackDelegate updateCallback)
{
_updateCallback = updateCallback;
}
public void GetData()
{
var thread = new Thread(GetInvoicingData)
{
IsBackground = true
};
thread.Start();
}
private void GetInvoicingData()
{
// Not sure whether "DAC" is a static class, if it needs to be constructed
// in the DataRetriever's constructor, or passed to it as a parameter
_updateCallback(DAC.GetInvoicingAccounts());
}
}
As you can see, all the thread code is now in a separate class DataRetriever, and a delegate provided when constructing it to enable the retrieved data to be passed back to the form once the retrieval is complete. The method that handles the callback ensures that the call is marshalled to the UI thread to prevent cross-thread exceptions.
I would like to point out that this is not presented as the "best" way to do this, but merely as an answer to the question (how to separating threading code into a separate class). As others have mentioned, there are already mechanisms in place to do this sort of thing (e.g. BackgroundWorker). Some complexity has been omitted for clarity. For example, in the implementation presented here, if you were to call GetData() multiple times (with each call occurring before the previous ones have returned their data), you would have multiple queries occurring simultaneously, and as they are running asynchronously, may return their data in an arbitrary order. This may or may not be an issue in your case.

Categories

Resources