I've successfully created a simple server and client application in C# that communicate asynchronously between the server and multiple clients, i used the following Microsoft Docs to create it:
https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example
https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-client-socket-example
They are both working fine, but my question is, i want to execute an action every second on the server and i don't know the best way to go about it. Should i use something like the Timer class to do it? Is using a Timer interfere in any way with the calls that the server is receiving from the clients?
I would suggest using some form of Thread.Sleep or calling await on a method with a Task.Delay. See an example here.
Yes a timer is a good way to it.
I have something similar for a Blazor component called a Sprite, where I perform a movement of an image everytime the timer event goes off.
In my case my subscriber is an interface, ISpriteSubscriber:
namespace DataJuggler.Blazor.Components.Interfaces
{
#region interface ISpriteSubscriber
/// <summary>
/// This interface is used by the AnimationManager to notifiy callers that a refresh occurred.
/// </summary>
public interface ISpriteSubscriber
{
#region Methods
#region Refresh()
/// <summary>
/// This method will call StateHasChanged to refresh the UI
/// </summary>
void Refresh();
#endregion
#region Register(Sprite sprite)
/// <summary>
/// This method is called by the Sprite to a subscriber so it can register with the subscriber, and
/// receiver events after that.
/// </summary>
void Register(Sprite sprite);
#endregion
#endregion
#region Properties
#region ProgressBar
/// <summary>
/// This is used so the ProgressBar is stored and available to the Subscriber after Registering
/// </summary>
ProgressBar ProgressBar { get; set; }
#endregion
#endregion
}
#endregion
}
public ISpriteSubscriber Subscriber { get; set; }
In my Start event, I create the Timer:
public void Start()
{
this.Timer = new Timer();
this.Timer.Interval = this.interval;
this.Timer.Elapsed += Timer_Elapsed;
this.Timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
// if a subscriber (returns true if Subscriber != null)
if (HasSubscriber)
{
// Notify Subscriber
Subscriber.Refresh();
}
}
public void Refresh()
{
// do your actions here
}
public void Register(Sprite sprite)
{
// If the sprite object exists
if (NullHelper.Exists(sprite))
{
// if this is the RedCar
if (sprite.Name == "RedCar")
{
// Set the RedCar
RedCar = sprite;
}
else
{
// Set the WhiteCar
WhiteCar = sprite;
}
}
}
The Refresh event is where I move an image (by random numbers in my example).
One tip When using a timer that goes off as often as you have it, I usually put something like a NotificationInProgress flag or something in case one operation takes longer than a second.
Maybe in your use case it is ok to have multiple messages, but sometimes you need to wait on one to finish before completing the next.
public bool NotificationInProgress { get; set; }
Then before you notify a Subscriber I test
if (!NotificationInProgress)
{
// send your message.
}
If you want to see an open source Blazor sample project where I demonstrate simple animations that this code came from, it is here:
https://github.com/DataJuggler/DataJuggler.Blazor.Components
Maybe it will give you some ideas on how to arrange your project.
Related
Can someone explain whether or not I can call the below class "thread safe"?
As far as I know, we can call something thread safe if we are not breaking existing functionality
Example:
public class BackgroundWorker
{
private readonly IDictionary<string, RunningTask> _runningTasks = new ConcurrentDictionary<string, RunningTask>();
/// <summary>
/// Executes async job for the specified key, only one at a time.
/// </summary>
/// <param name="key"></param>
public void Enqueue(string key)
{
if (_runningTasks.ContainsKey(key))
{
_runningTasks[key].Repeat = true;
return;
}
_runningTasks[key] = new RunningTask();
ExecuteTask(key);
}
private void ExecuteTask(string key)
{
Task.Run(() =>
{
// Do something
if (_runningTasks[key].Repeat)
{
_runningTasks[key].Repeat = false;
ExecuteTask(key);
return;
}
_runningTasks.Remove(key);
});
}
private class RunningTask
{
/// <summary>
/// Flag to repeat a task after completion.
/// </summary>
public bool Repeat { get; set; }
}
}
I don't think so because _runningTasks is shared object and your method Enqueue is writing on this shared object. For example its possible when one thread already executed line number y, another thread will evaluate condition check in line number x as true - which might not be intention.
public void Enqueue(string key)
{
if (_runningTasks.ContainsKey(key)) /*say line no : x */
{
_runningTasks[key].Repeat = true;
return;
}
_runningTasks[key] = new RunningTask(); /*say line no:y*/
ExecuteTask(key);
}
Using ConcurrentDictionary will just ensure no two threads can read/write to/from the dictionary same time.
To your second point :
As far as I know, we can call something thread safe if we are not
breaking existing functionality
No this is not the definition of thread safe (might be ok to say one of desirable outcome in multi threaded environment) I would recommend to read this post for official meaning rather.
I'm trying to find the correct approach to communicating back and forth between the View and Model/Adapter Layers in an MVC model. The following is some psuedo-code of my issue, and what I want it to do. See the comments in the MyAdapter.ImportStuff method for explanations.
public class MyView : System.Windows.Forms.UserControl
{
private MyContoller Ctrl = new MyContoller();
public MyView()
{
}
private void OnButtonClick()
{
Ctrl.DoSqlStuffNow();
TellUserImportFinished();
}
public void TellUserThingsHaveBeenDeleted()
{
this.label1.Text = "Stuff deleted...";
}
public void TellUserHowManyRowsHaveBeenInserted(int rowCount)
{
this.label2.Text = $"Number of rows inserted: {rowCount}...";
}
public void TellUserComplexQueriesAreDone()
{
this.label3.Text = "Complex queries are done...";
}
public void TellUserImportFinished()
{
System.Windows.Forms.MessageBox.Show("Success!");
}
}
internal class MyContoller
{
MyAdapter Adpt = new MyAdapter();
internal void DoSqlStuffNow()
{
object someParameter = new object();
Adpt.ImportStuff(someParameter);
}
}
internal class MyAdapter
{
internal void ImportStuff(object someParameter)
{
SqlConnection sqlConnection = new SqlConnection("connection");
// All of this has to happen in one connection/transaction.
// It should not be broken into multiple methods
DeleteFromTable1();
DeleteFromTable2();
// Now I want to tell the user delete is complete!
MakeTempTable();
InsertIntoTempTable(someParameter);
int rowCount = ImportIntoTable1();
// Now I want to tell the user how many rows were just inserted!
DoComplexQuery();
DoAnotherComplexQuery();
// Now I want to tell the user complex queries are done!
ImportIntoTable2();
DropTempTable();
// Presumably, I can say "success" when this function returns, which is fine
}
}
My particular case is even worse since the Controller/Adapter are actually static classes, so event's aren't fun to deal with, but I'm not even sure how best to handle it in this simple case.
Any advice would be appreciated!
I would not over complicate stuffs. Looking at the design you have I would go with Events in the Adapter class and bindings in the MyView.
You create 4 events based on what you want to notify. As everything is happening in a single method you could also have 1 event and 4 different status. Though, I don't like this approach since it would require a bunch of IFs later in the event handlers.
You can write your own delegates of course but for simplicity I did use the EventHandler class.
public event EventHandler DeleteCompleted;
//int: the number of rows inserted
public event EventHandler<int> RowsInserted;
public event EventHandler ComplexQuerycCompleted;
//bool: if the operation completed successfully.
public event EventHandler<bool> OperationCompleted;
Another advantage of multiple events is that let's say a part of your app only wants to know when the operation is completed but nothing else you would only subscribe to that specific event.
Modify your class to call the events where ever you need.
internal class MyAdapter
{
public event EventHandler DeleteCompleted;
public event EventHandler<int> RowsInserted;
public event EventHandler ComplexQuerycCompleted;
public event EventHandler<bool> OperationCompleted;
internal void ImportStuff(object someParameter)
{
SqlConnection sqlConnection = new SqlConnection("connection");
// All of this has to happen in one connection/transaction.
// It should not be broken into multiple methods
DeleteFromTable1();
DeleteFromTable2();
// Now I want to tell the user delete is complete!
this.DeleteCompleted?.Invoke(this, new EventArgs());
MakeTempTable();
InsertIntoTempTable(someParameter);
int rowCount = ImportIntoTable1();
// Now I want to tell the user how many rows were just inserted!
this.RowsInserted?.Invoke(this, rowCount);
DoComplexQuery();
DoAnotherComplexQuery();
// Now I want to tell the user complex queries are done!
this.ComplexQuerycCompleted.Invoke(this, new EventArgs());
ImportIntoTable2();
DropTempTable();
// Presumably, I can say "success" when this function returns, which is fine
this.OperationCompleted?.Invoke(this, true);
}
}
In your MyController class you can subscribe to the events you need. In this class you can implement the INotifyPropertyChanged (MVVM) so that you notify the MyView View about changes in from the adapter.
internal class MyContoller : INotifyPropertyChanged
{
MyAdapter Adpt = new MyAdapter();
public event PropertyChangedEventHandler PropertyChanged;
private int rowsInserted;
public int RowsInserted
{
get { return rowsInserted;}
set
{
if (rowsInserted == value)
return;
rowsInserted = value;
RaisedPropertyChanged(nameof(RowsInserted));
}
}
internal MyContoller()
{
//Remember to remote the event subscriptions calling:
// Adpt.RowsInserted -= OnRowsInserted
Adpt.RowsInserted += OnRowsInserted;
}
internal void DoSqlStuffNow()
{
object someParameter = new object();
Adpt.ImportStuff(someParameter);
}
/// <summary>
/// Raiseds the property changed.
/// </summary>
/// <param name="propertyName">Property name.</param>
protected void RaisedPropertyChanged([CallerMemberNameAttribute] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Called when the Rows has been inserted in the <see cref="MyAdapter"/>
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="numberOfRows">The Number of rows in inserted</param>
void OnRowsInserted(object sender, int numberOfRows)
{
//Notify the UI about objects inserted
RowsInserted = numberOfRows;
}
}
Later in your view you bind the properties from the MyController to the UI Controls you are using to reflect the changes.
Read about Databinding here.
I am not clear when you said " the Controller/Adapter are actually static classes" but I think the above can really help you.
Another option of course is using ReactiveUI, but this one would require you to learn about Rx.Net and programming in a reactive way.
I've written a DLL that does a bunch of stuff. One of the things it does is to search through a lot of incoming messages for a specific message, clean up the message, and raise an event when the message is found, and pass the data via the EventArgs.
Currently the DLL is working but the routine that searches for the message is slowing everything down and making the system slow to respond because there is so much data to go through.
I would like to move this searching to it's own thread, and once the message is found have it raise an event on the main thread and pass the message data to the main thread. I know how to make a thread to do the work, but I do not know how to make the thread raise the event on the main thread and pass the data to it. Could someone tell me how to do this, or point to an example of it?
I've tried creating a delegate and triggering an event, which works but when I try to pass the data I get a cross thread exception.
Some details that may be important. There most likely won't be a GUI at all and will probably remain a console application. Messages will always be coming in and the DLL has to continuously search them. The message the DLL is looking for may come as often as 1 couple times a second or it may be days between the messages.
Update for a real simple project illustrating what I would like to do. This code is rough cause I threw it together to test this out.
If you follow the code you will see that everything runs fine until the line in the CollectData function where:
StatusUpdated(this, null);
is called. At this point it causes the cross thread exception because of the UI thread and the data Collection thread. I know I can fix this by using an invoke on the UI thread, but as mentioned above this will most likely not be used with any sort of GUI (but it should be able to handle it). So the cross thread exception needs to be fixed in the BuildResultsManager class, I think in the function BRMgr_StatusUpdated. How do I get the data (in this case the value of currentVal) to the UI thread without changing any code in the MainWindow class.
You can run this by creating a solution with 2 projects, 1 for the first 2 files as a dll. The second as a wpf project, referencing the dll, and put a textbox named status on the form.
Main Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace BuildResultsManager
{
/// <summary>
/// Delegate to notify when data has changed
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
public delegate void StatusUpdatedEventHandler(object sender, EventArgs e);
/// <summary>
/// Connects to the PLC via PVI and reads in all the build results data, conditions it, updates values and reads/store into the database
/// </summary>
public class BuildResultsManager
{
#region events
// Change in The Build Results Manger Status
public event StatusUpdatedEventHandler StatusUpdated;
#endregion
#region Local variables
private Thread collectionThread;
private string statusMessage;
DataCollector dataCollection;
#endregion
#region Properties
/// <summary>
/// Current Status of the Build Results manager
/// </summary>
public String StatusMessage
{
get
{
return statusMessage;
}
private set
{
statusMessage = value;
if (StatusUpdated != null)
StatusUpdated(this, null);
}
}
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public BuildResultsManager()
{
StatusMessage = "successfully initialized";
// start the thread that will collect all the data
dataCollection = new DataCollector();
dataCollection.StatusUpdated += new DCStatusUpdatedEventHandler(BRMgr_StatusUpdated);
collectionThread = new Thread(new ThreadStart(dataCollection.CollectData));
collectionThread.Start();
}
/// <summary>
/// EVent to handle updated status text
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
void BRMgr_StatusUpdated(object sender, EventArgs e)
{
StatusMessage = dataCollection.currentVal.ToString();
}
#endregion
}
}
The class that will be doing all of the thread work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Threading;
using System.Threading;
namespace BuildResultsManager
{
/// <summary>
/// Delegate to notify when data has changed
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
public delegate void DCStatusUpdatedEventHandler(object sender, EventArgs e);
/// <summary>
/// Handles all of the data collection and conditioning
/// </summary>
class DataCollector
{
#region events
// Change in The Build Results Manger Status
public event DCStatusUpdatedEventHandler StatusUpdated;
#endregion
private const long updateInterval = 1000;
private Stopwatch updateTimer;
public int currentVal;
#region local variables
private bool shouldStop;
#endregion
/// <summary>
/// Default Constructor
/// </summary>
public DataCollector()
{
shouldStop = false;
updateTimer = new Stopwatch();
updateTimer.Start();
}
/// <summary>
/// Main task that listens for new data and collects it when it's available
/// </summary>
public void CollectData()
{
currentVal = 5;
while (!shouldStop && currentVal < 10)
{
if(updateTimer.ElapsedMilliseconds > updateInterval)
{
currentVal++;
if (StatusUpdated != null)
{
StatusUpdated(this, null);
}
//reset the timer
updateTimer.Restart();
}
}
}
/// <summary>
/// Asks the thread to stop
/// </summary>
public void RequestStop()
{
shouldStop = true;
}
}
}
Code behind for the wpf project:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Local variables
private string BRMgrStatus;
private BuildResultsManager.BuildResultsManager BRMgr;
#endregion
public MainWindow()
{
InitializeComponent();
// create an instance of the build manager
BRMgr = new BuildResultsManager.BuildResultsManager();
if(BRMgr != null)
{
status.Text = BRMgr.StatusMessage;
BRMgr.StatusUpdated += new StatusUpdatedEventHandler(BRMgr_StatusUpdated);
}
}
/// <summary>
/// EVent to handle updated status text
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
void BRMgr_StatusUpdated(object sender, EventArgs e)
{
BuildResultsManager.BuildResultsManager brm;
brm = (BuildResultsManager.BuildResultsManager)sender;
status.Text = brm.StatusMessage;
}
}
If you don't use a GUI there's no need to execute things on the same thread, just protect non-thread-safe resources with a locking mechanism (lock, mutex, etc) to avoid concurrent access and you're good.
I want to create a windows service that will create x number of threads that wake up every x number of minutes and do some work.
I think the task scheduling or parallel framework is a bad fit for this type of work as it is best suited for work that starts, completes and finishes rather than is constant.
Should I look at utilising a thread pool for this approach or does anyone have any advice for a good solution?
Really, it sounds like you only need one thread.
Here's a helper class that I created for exactly this kind of thing. Here's how you use it:
class MyPeriodicTasks : PeriodicMultiple
{
// The first task will start 30 seconds after this class is instantiated and started:
protected override TimeSpan FirstInterval { get { return TimeSpan.FromSeconds(30); } }
public MyPeriodicTasks()
{
Tasks = new[] {
new Task { Action = task1, MinInterval = TimeSpan.FromMinutes(5) },
new Task { Action = task2, MinInterval = TimeSpan.FromMinutes(15) },
};
}
private void task1() { /* code that gets executed once every 5 minutes */ }
private void task2() { /* code that gets executed once every 15 minutes */ }
}
Then, to start the tasks:
var tasks = new MyPeriodicTasks();
tasks.Start();
And during service shutdown:
tasks.Shutdown();
(alternatively, call Start with backgroundThread: true, then you don't need to call Shutdown, but then a task may just get terminated right in the middle of doing something)
Here's the actual code:
/// <summary>
/// Encapsulates a class performing a certain activity periodically, which can be initiated once
/// and then permanently shut down, but not paused/resumed. The class owns its own separate
/// thread, and manages this thread all by itself. The periodic task is executed on this thread.
/// <para>The chief differences to <see cref="System.Threading.Timer"/> are as follows. This
/// class will never issue overlapping activities, even if an activity takes much longer than the interval;
/// the interval is between the end of the previous occurrence of the activity and the start of the next.
/// The activity is executed on a foreground thread (by default), and thus will complete once started,
/// unless a catastrophic abort occurs. When shutting down the activity, it's possible to wait until the
/// last occurrence, if any, has completed fully.</para>
/// </summary>
public abstract class Periodic
{
private Thread _thread;
private CancellationTokenSource _cancellation;
private ManualResetEvent _exited;
/// <summary>
/// Override to indicate how long to wait between the call to <see cref="Start"/> and the first occurrence
/// of the periodic activity.
/// </summary>
protected abstract TimeSpan FirstInterval { get; }
/// <summary>
/// Override to indicate how long to wait between second and subsequent occurrences of the periodic activity.
/// </summary>
protected abstract TimeSpan SubsequentInterval { get; }
/// <summary>
/// Override with a method that performs the desired periodic activity. If this method throws an exception
/// the thread will terminate, but the <see cref="LastActivity"/> will occur nevertheless.
/// </summary>
protected abstract void PeriodicActivity();
/// <summary>
/// Override with a method that performs an activity on the same thread as <see cref="PeriodicActivity"/> during
/// shutdown, just before signalling that the shutdown is complete. The default implementation of this method
/// does nothing. This method is guaranteed to be called during a shutdown, even if the shutdown is due to an
/// exception propagating outside of <see cref="PeriodicActivity"/>.
/// </summary>
protected virtual void LastActivity() { }
/// <summary>
/// Returns false before the first call to <see cref="Start"/> and after the first call to <see cref="Shutdown"/>;
/// true between them.
/// </summary>
public bool IsRunning { get { return _cancellation != null && !_cancellation.IsCancellationRequested; } }
/// <summary>
/// Schedules the periodic activity to start occurring. This method may only be called once.
/// </summary>
/// <param name="backgroundThread">By default (false) the class will use a foreground thread, preventing application shutdown until the thread has terminated. If true, a background thread will be created instead.</param>
public virtual void Start(bool backgroundThread = false)
{
if (_thread != null)
throw new InvalidOperationException(string.Format("\"Start\" called multiple times ({0})", GetType().Name));
_exited = new ManualResetEvent(false);
_cancellation = new CancellationTokenSource();
_thread = new Thread(threadProc) { IsBackground = backgroundThread };
_thread.Start();
}
private volatile bool _periodicActivityRunning = false;
/// <summary>
/// Causes the periodic activity to stop occurring. If called while the activity is being performed,
/// will wait until the activity has completed before returning. Ensures that <see cref="IsRunning"/>
/// is false once this method returns.
/// </summary>
public virtual bool Shutdown(bool waitForExit)
{
if (waitForExit && _periodicActivityRunning && Thread.CurrentThread.ManagedThreadId == _thread.ManagedThreadId)
throw new InvalidOperationException("Cannot call Shutdown(true) from within PeriodicActivity() on the same thread (this would cause a deadlock).");
if (_cancellation == null || _cancellation.IsCancellationRequested)
return false;
_cancellation.Cancel();
if (waitForExit)
_exited.WaitOne();
return true;
}
private void threadProc()
{
try
{
_cancellation.Token.WaitHandle.WaitOne(FirstInterval);
while (!_cancellation.IsCancellationRequested)
{
_periodicActivityRunning = true;
PeriodicActivity();
_periodicActivityRunning = false;
_cancellation.Token.WaitHandle.WaitOne(SubsequentInterval);
}
}
finally
{
try { LastActivity(); }
finally { _exited.Set(); }
}
}
}
/// <summary>
/// <para>Encapsulates a class performing multiple related yet independent tasks on the same thread
/// at a certain minimum interval each. Schedules the activity that is the most late at every opportunity,
/// but will never execute more than one activity at a time (as they all share the same thread).</para>
/// </summary>
public abstract class PeriodicMultiple : Periodic
{
/// <summary>
/// Used to define the activities to be executed periodically.
/// </summary>
protected sealed class Task
{
/// <summary>The activity to be performed.</summary>
public Action Action;
/// <summary>The mimimum interval at which this activity should be repeated. May be delayed arbitrarily though.</summary>
public TimeSpan MinInterval;
/// <summary>Stores the last time this activity was executed.</summary>
public DateTime LastExecuted;
/// <summary>Calculates by how much this activity has been delayed. Is used internally to pick the next activity to run. Returns negative values for activities that aren't due yet.</summary>
public TimeSpan DelayedBy()
{
if (LastExecuted == default(DateTime))
return TimeSpan.FromDays(1000) - MinInterval; // to run shortest interval first when none of the tasks have ever executed
else
return (DateTime.UtcNow - LastExecuted) - MinInterval;
}
}
/// <summary>If desired, override to provide a custom interval at which the scheduler
/// should re-check whether any activity is due to start. Defaults to 1 second.</summary>
protected override TimeSpan SubsequentInterval { get { return TimeSpan.FromSeconds(1); } }
/// <summary>Initialise this with the list of activities to be executed.</summary>
protected IList<Task> Tasks;
/// <summary>For internal use.</summary>
protected sealed override void PeriodicActivity()
{
TimeSpan maxDelay = TimeSpan.MinValue;
Task maxDelayTask = null;
foreach (var task in Tasks)
{
var delayedBy = task.DelayedBy();
if (maxDelay < delayedBy && delayedBy > TimeSpan.Zero)
{
maxDelay = delayedBy;
maxDelayTask = task;
}
}
if (maxDelayTask != null)
{
maxDelayTask.LastExecuted = DateTime.UtcNow;
maxDelayTask.Action();
}
}
}
The thread spends most of the time sleeping, but it does wake up every 1 second to check if a task is due. This 1 second interval is probably too short for intervals like 15 minutes, so reduce it to something like 30 seconds instead (that would be the SubsequentInterval).
Hope it's useful!
It makes very little sense to start x threads to do x jobs when you intentionally don't let them do any work at all for y minutes. Just have one thread do x jobs. It will take x times longer to complete the work (a bit less, actually) but that's no issue at all as long as that takes less than y minutes.
Additional benefits from this is that the service cannot easily impact the responsiveness of the machine, other cores remain available. And that your code becomes a heckofalot easier to implement and debug.
Use the System.Threading.Thread timer to activate the work. The callback runs on a threadpool thread. Starting and stopping the service is easy, just enable/disable that timer.
Do you really need those threads to run constantly and then wake up after x minutes? I think you may want to consider using an existing scheduler library like Quartz.NET which handle running the tasks for you.
I have two suggestions for you. First, for building your service, check out TopShelf. It removes all the pain of setting up a Windows service.
Second, you can use the Observable class to create a timer without resorting to writing Timer specific code or Quartz (a pain to configure!).
Here's some sample code:
public class MyService
{
private IDisposable Timer;
public void Start()
{
Timer = ObservableHelpers
.CreateMinutePulse(15) // check every 15 seconds if it's a new minute
.Subscribe(i => DoSomething());
}
public void Stop()
{
if(Timer != null)
{
Timer.Dispose();
Timer = null;
}
}
public void DoSomething()
{
// do your thing here
}
}
public static class ObservableHelpers
{
/// <summary>
/// Returns an observable that pulses every minute with the specified resolution.
/// The pulse occurs within the amount of time specified by the resolution (in seconds.)
/// Higher resolution (i.e. lower specified number of seconds) may affect execution speed.
/// </summary>
/// <returns></returns>
public static IObservable<int> CreateMinutePulse(int resolution)
{
return Observable
.Interval(TimeSpan.FromSeconds(resolution.SetWithinRange(1, 59)))
.Select(i => DateTime.Now.Minute)
.DistinctUntilChanged();
}
}
Well, I belive your problem seems to be solved with Producer Consumer Design pattern.
Producer will be the single main thread, and the all other threads will be the consumer thread.
From my opinion it will be best have independent threads than using thread pool.
Eg:
private Thread Worker;
public Consumer()
{
Worker = new Thread(ProcessMethod);
}
Now in processmethod you do what you have to do.
Create as many Consumer as you want.
Is this an appropriate way of handling cross-thread operations?
Should I use a new property name, something like "EditValueThreadSafe" instead of overriding "EditValue"? I don't think there is an issue with the changes to the implementation of EditValue, as the base property is called regardless.
namespace MyApplication.Components
{
using System.Windows.Forms;
/// <summary>
/// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class.
/// </summary>
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
/// <summary>
/// Gets or sets the edit value.
/// </summary>
/// <value>The edit value.</value>
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate
{
this.SetEditValue(value);
}));
}
else
{
this.SetEditValue(value);
}
}
}
/// <summary>
/// Sets the edit value.
/// </summary>
/// <param name="value">The value.</param>
private void SetEditValue(object value)
{
base.EditValue = value;
}
}
}
You can also delegate to another method that does the work, and in that method, if on the wrong thread, (BeginInvoke returns true), then call the same method back again. Doing that that eliminates the need to duplicate code.
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
SetValue(value);
}
}
private void delegate SetValueDlg(object valeu);
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
(SetValueDlg)SetValue, // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
You can also use the Action() generic class to eliminate need to create explicit delegate class...
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get { return base.EditValue; }
set { SetValue(value); }
}
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
new Action<object>(SetValue), // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
It's thread-safe, yes, though be wary of overriding a property and fundamentally changing the behaviour. Changing the implentation is fine, but this property now behaves very differently, removing the possibility of a specific exception but introducing a possible deadlock or blocking condition, which impacts on the calling code.
So yes, this is the correct use of InvokeRequired & Invoke, but I'd recommend creating a separate, purpose-specific and thread-safe property that is advertised as such.
My UI methods like yours end up looking like this:
public void setStatusLabelText(String s)
{
if (footerStatusLabel.InvokeRequired) {
StringUpdateInvokeDelegate callback = new StringUpdateInvokeDelegate(setStatusLabelText);
this.Invoke(callback, new object[] { s });
}
else {
this.footerStatusLabel.Text = s;
}
}
(this may be old for .net these days - but the point is that you can just do the operation inside this method if you are already on the right thread - makes it a little less irritating to read, but still annoying compared to Java, IMO).
I'll inject my 2 cents here. The actual calls to InvokeRequired/BeginInvoke/Invoke are not entirely thread safe. (see Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?) I would recommend finding some way of isolating the calls to these in a single place, utility api, extension method, or the like. In the article above there is complete code for a class that wraps a delegate to provide thread-safe behavior.