Hello yeah I'm asking this question a second time, sorry about that but I don't know how to bump previous question. I'll explain more in depth my problem in a more completed example.
Instead of writing like 300+ Event classes in 300 class files which I may have to do if this doesn't work, so they can do little timed jobs like this example job below in a server project.
What i'm trying to avoid is writing a bunch of classes and simply just write everything more compacted in structure of whatever i'm working on.
To sum it up, i'm mixing 90% functional programming and want to give some function some delayed timed event, without creating the new timed event in a separate class then running back and forth through the files looking how everything is linked up, but this way everything can be seen so you can find bugs and whatnot much faster as everything is right in front of you, kinda like writing loop code, but with delay.
All I have right now is one thread which processes events, deletes events which have been stopped, keeps re-running events which don't stop after one cycle and of course waiting until some events can be ran.
If anyone knows a better way to do what i'm trying to do maybe some built-in C# Event system? Which is preferably simple.
class Event {
private Action action;
private bool stopped;
public Event(long tick, Action action) {
this.tick = tick;
this.action = action;
this.lastRun = Environment.TickCount;
}
public void stop() {
stopped = true;
}
public bool canRun() { //blah ignore just showing what I plan to do
if (stopped)
return false;
return (Environment.TickCount - lastRun) > tick;
}
public void run() {
this.lastRun = Environment.TickCount;
action();
}
//... other methods
}
class Test {
string t;
public void setT(string t) {
this.t = t;
}
public void stuff() {
Console.WriteLine(a);
}
}
class ImportantWork {
public static void Main(string[] args) {
someDeepMethod();
}
void someDeepMethod() {
Test t = new Test();
t.setT("secondTime");
//Here is where the problem occurs.
Server.registerEvent(new Event(5000, () => {
this.stop(); //<-- Error how I call this from this new Event instance.
stop(); //<-- Also error
//Event.stop(); //<-- haha may work if it was static but thats stupid
t.stuff();
Console.WriteLine("thirdTime");
}));
t.setT("firstTime");
t.stuff();
}
}
Expected output:
firstTime
...waits 5 seconds...
secondTime
thirdTime
I don't know how you'd be able to do that inline like that. Why can't you use some kind of set-function and make it two lines?
MyEvent newEvent;
Server.registerEvent((newEvent = new MyEvent(5000)));
newEvent.setAction(() => {
newEvent.stop();
t.stuff();
Console.WriteLine("thirdTime");
});
It seems to me like there's some kind of structural issue with your design. I'm assuming that the example you provided was not actually what you were working with, just a simple example to address the problem you're having. If it is, however, the example you're working with why don't you just add a boolean flag in the constructor to tell the instance whether or not to call this.stop() on itself - instead of requiring it specified in the Action?
Best of luck!
Related
I've attempted to make a simple step mode for an algorithm I'm running, and here is how it looks like:
public async Task<bool> AStarAlgorithmAsync(PFSquare curr = null)
{
// some algorithm code here
foreach(var square in Sorroundings)
{
if (SteppedMode)
{
await Task.Run(Pause);
}
if (await AStarAlgorithmAsync(square))
{
return true;
}
}
}
In my application, I have a Boolean called SteppedMode that decides if the algorithm should run one iteration per click event.
Pause() looks like this:
private void Pause()
{
while (!ContinueStep) { }
ContinueStep = false;
return;
}
And in another part of my (GUI) application I have an event which sets the boolean ContinueStep to true which in theory should end the while loop and continue the algorithm function. Currently this bit of code locks my GUI thread up and I'm almost certain there is a better way to do this.
I'm trying to get my algorithm function to run one iteration, wait for a click from the user and only then continue running the algorithm. Is there an easier and cleaner way to do this?
(This is a GUI application, not a console application.)
Your property is moonlighting as a method.
It makes no sense to set a property, to then have that property revert back to its original state immediately. As a consumer, I would be majorly confused by that behavior. Think about this code:
var myObj = new MyObject();
myObj.MyBoolean = true;
Console.WriteLine(myObj.MyBoolean); // FALSE!?
It just doesn't make sense.
The only effect you want to trigger by setting this property is to execute some code. That's exactly what methods are supposed to be used for:
public void ContinueStep()
{
Console.WriteLine("I did some work");
}
So instead of this:
myObj.ContinueStep = true;
you should be doing this:
myObject.ContinueStep();
This doesn't lock up your UI thread, while also being a lot more sensical to your consumer. The method suggests that some action will be taken (which may or may not lead to state changes in the object - that's a contextual expectation).
Infinite recursion
As an aside; based on your code, AStarAlgorithmAsync is a recursive function, and seemingly infinitely so. There doesn't seem to be an ending condition.
Every recursive level will interate over the first surrounding and then trigger the next level, which again will interate over the first surrounding and then trigger the next level, which again ...
That can't be right, but it's unclear to me how to fix it as the bigger picture is not explained in your question
A simple implementation
What I'm trying to do is get my algorithm function to run one iteration, wait for a click from the user and only then continue running the algorithm, is there an easier and cleaner way to do this?
A simple example of such a thing:
private int _index = 0;
private List<object> _myList = ...; // assume this list contains some elements
public void ProcessNextObject()
{
if(_index < _myList.Length)
{
Process(_myList[_index]);
_index++;
}
}
private void Process(object o)
{
Console.WriteLine("Processing this object!");
}
You can then hook up your click event to call ProcessNextObject().
Note that in this example, the list is processed once and cannot be processed again. By manipulating the index value, you can change that behavior as you like.
this is the best way I can think of doing this. Could you give me so hints as to whether this is the correct way or if there is a more efficient way of doing it.
My situation is:
Each time the frame is Update()'ed (Like in XNA) I want to check if something has happened.. Like if the timer for that screen has been running for over 2000 milliseconds. But I only want it to fire once, not every time the frame is updated. This would cause a problem:
if(totalMilliseconds > 2000)
{
this.Fader.FadeIn();
}
So I came up with this method that I have implemented in the GameScreen class that looks like this:
public bool RunOnce(string Alias, bool IsTrue)
{
if (!this.Bools.ContainsKey(Alias))
this.Bools.Add(Alias, false);
if (IsTrue && !this.Bools[Alias])
{
this.Bools[Alias] = true;
return true;
}
else
return false;
}
This basically checks if the passed if statement boolean is true, if it is then it fires once and not again unless the Bool["Alias"] is set back to false. I use it like this:
if(this.RunOnce("fadeInStarted", totalMilliseconds > 2000))
{
this.Fader.FadeIn();
}
This will then only run one time and I think is quite easily readable code-wise.
The reason I have posted this is for two reasons.. Firstly because I wanted to show how I have overcome the problem as it may be of some help to others who had the same problem.. And secondly to see if I have missed an obvious way of doing this without creating a manual method for it, or if it could be done more efficiently.
Your method is interesting, I don't see a problem with it, you've essentially created a new programming construct.
I haven't encountered this situation a lot so what I have done in this situation is always start with the untidy approach:
bool _hasFadedIn = false;
.
if(totalMilliseconds > 2000 && !_hasFadedIn)
{
this.Fader.FadeIn();
_hasFadedIn = true;
}
And 90% of the time I leave it like that. I only change things if the class starts growing too big. What I would do then is this:
_faderControl.Update(totalMilliseconds);
Put the logic for fader control into a separate class, so:
class FaderControl
{
bool _hasFadedIn=false;
public void Update(int totalMilliseconds)
{
if (_hasFadedIn)
return;
if (totalMilliseconds <= 2000)
return;
this.Fader.FadeIn();
_hasFadedIn=true;
}
}
It can be modified to make it configurable, like reseting, setting "start", "end", fadein time, or also controlling fadeout too.
Here's how I would approach this problem.
These are your requirements:
You have arbitrary pieces of logic which you want to execute inside of your Update().
The logic in question has a predicate associated with it which determines whether the action is ready to execute.
The action should execute at most once.
The core concept here is "action with an associated predicate," so create a data structure which represents that concept:
public class ConditionalAction
{
public ConditionalAction(Action action, Func<Boolean> predicate)
{
this.Action = action;
this.Predicate = predicate;
}
public Action Action { get; private set; }
public Func<Boolean> Predicate { get; private set; }
}
So now, your example becomes
var action = new ConditionalAction(
() => this.Fader.FadeIn(),
() => totalMilliseconds > 2000);
In your Update() you need something that can execute these conditional actions:
public void Update(GameTime time)
{
// for each conditional action that hasn't run yet:
// check the action's predicate
// if true:
// execute action
// remove action from list of pending actions
}
Because their predicates are probably unrelated, actions don't necessarily run in order. So this isn't a simple queue of actions. It's a list of actions from which actions can be removed in arbitrary order.
I'm going to implement this as a linked list in order to demonstrate the concept, but that's probably not the best way to implement this in production code. Linked lists allocate memory on the managed heap, which is generally something to be avoided in XNA. However, coming up with a better data structure for this purpose is an exercise best left for another day.
private readonly LinkedList<ConditionalAction> pendingConditionalActions =
new LinkedList<ConditionalAction>();
public void Update(GameTime time)
{
for (var current = pendingConditionalActions.First; current != null; current = current.Next)
{
if (current.Value.Predicate())
{
current.Value.Action();
pendingConditionalActions.Remove(current);
}
}
}
public void RegisterConditionalAction(ConditionalAction action)
{
pendingConditionalActions.AddLast(action);
}
Registered actions will wait until their predicates become true, at which point they will be executed and removed from the list of pending actions, ensuring that they only run once.
I have a function called ExecuteCommand that does things based on a user's input. These things can range from simply doing a Console.Writeline(), checking a check box on my form, or simulating keystrokes to another process, completely independent from my own. The function runs on a separate thread, so changing the UI will requiring some invoking. I have 2 ways of doing it... one of which I'm not sure is a good way but it's very easy.
Code below, the 3rd line is what I have a question with:
private void ExecuteCommand()
{
this.Invoke((MethodInvoker)delegate()
{
if (current_line_index < command_que.Count)
{
current_line = command_que[current_line_index];
if (current_line.StartsWith(">>Auto Enter"))
{
chkAutoEnter.Checked = false;
}
else if (current_line.StartsWith("+WinWait("))
{
string title_to_wait_for = current_line;
title_to_wait_for = title_to_wait_for.Remove(0, "+WinWait(\"".Length);
title_to_wait_for = title_to_wait_for.Remove(title_to_wait_for.Length - 2, 2);
t_WinWait = new Thread(() => WinWait(title_to_wait_for));
t_WinWait.Name = "WinWait";
t_WinWait.Start();
}
}
});
}
The code works perfectly... but I am not sure if it's good practice.
Alternativly, I know I can do something like this to change the UI:
private delegate void CheckCheckBoxHandler(bool checked);
private void CheckCheckBox(bool checked)
{
if (this.chkAutoEnter.InvokeRequired)
{
this.chkAutoEnter.Invoke(new CheckCheckBoxHandler(this.CheckCheckBox), checked);
}
else
{
chkAutoEnter.Checked = checked;
}
}
But as I have multiple controls on my form that will be changed from another thread, I'd have to add a bunch of functions to do that, versus the simple method in the first example.
Is the first way bad in anyway? Are there any risks involved I haven't come across yet? It seems to good to be true...
Thanks!
No it's not bad. It doesn't matter which control that you call Invoke on since they all have the same effect. Invoke calls the delegate on the thread that owns the control - as long as all your controls are owned by the same thread, then there is no difference.
The application takes a lot of database queries. Request is created after the event made by the user or through the use of several timer (10 sec tick).
The problem occurs when the database server suddenly becomes unavailable. This causes a huge amount of on-screen messages containing information about the error in the connection.
I would like to achieve a situation in which a failed open call will freeze the application and open a single window that indicates a problem where the connection attempt will be retried every X seconds (plus a progress bar). If the connection is restored window is closed and the application will unlock.
How to do it? Please assumptions / guidelines or examples of ready-made solutions.
So if I understand you right, it's a usability problem. Your goal is for your users to be happy & confident that all is well, whilst waiting for a db connection. You don't want: panicky users pressing random buttons, phoning for help and complaining. You don't want a load of meaningless technical error messages; nor a frozen app with no messages. But you will accept a temporarily frozen app with a good helpful message.
Good usability doesn't come cheap. If you want to allow the user to cancel, then you have to learn some multi-threading. For that, I'd start here: http://msdn.microsoft.com/en-us/library/ms951089.aspx. You can avoid this if you are satisfied with a static message saying 'please wait, database connection may take up to xxx seconds...'.
I take a wild guess that your WinForms app calls the database from lots of places, but you'd like something that doesn't take days of re-writing.
The simplest single-threaded solution I can think of is to define a PleaseWaitForm and a 'wrapper' method, which I'll call DoWithPleaseWait(), which will go round all your business logic/data access calls, showing and hiding the please wait form:
namespace WinFormsPleaseWaitExample
{
//You don't need these 2 lines if you have .Net 3 or later
public delegate void Action();
public delegate TResult Func<TResult>();
//
public partial class Form1 : Form
{
private readonly Form pleaseWaitForm;
public Form1()
{
InitializeComponent();
pleaseWaitForm = new PleaseWaitForm {Owner = this};
}
private void button1_Click(object sender, EventArgs e)
{
var result= DoWithPleaseWait(delegate { return SomeBusinessLayerClass.ADataRetrieval("boo"); });
MessageBox.Show(result.ToString());
}
private void button2_Click(object sender, EventArgs e)
{
DoWithPleaseWait(delegate { SomeBusinessLayerClass.ADataOperation("boo"); });
}
public void DoWithPleaseWait(Action action)
{
pleaseWaitForm.Show();
action.DynamicInvoke();
pleaseWaitForm.Hide();
}
public TResult DoWithPleaseWait<TResult>(Func<TResult> func)
{
pleaseWaitForm.Show();
TResult result = (TResult)func.DynamicInvoke();
pleaseWaitForm.Hide();
return result;
}
}
public class SomeBusinessLayerClass
{
public static void ADataOperation(string someInput)
{
//Do something that might take several seconds...
Thread.Sleep(3000);
}
public static object ADataRetrieval(string someInput)
{
//Do something that might take several seconds...
Thread.Sleep(3000);
return someInput + " returned";
}
}
}
I made a program that loads a bunch of computer information. In the Form_Load event I have it initialize 3 (that number will grow) panels of information. One that has a bunch of unit information seems to make the program load rather slowly. I've tried to speed it up a bunch by switching from WMI to using Native calls, which helped a bunch. Soon though I'm going to have network information posted as well. I used to load that panel but i disabled it for a little bit till I work out the bugs in my other panels. So while learning how I can use a seperate thread to update my battery information I figured that I might be able to create seperate threads in my unit information panel so that it might could load faster. I dont know that any of my information would cause concurrent issues, but i can work on that.
I want to start small so what if i change this
private void Form1_Load(object sender, EventArgs e)
{
unitInformationPanel1.PopulateUnitInformation();
batteryInformationPanel1.InitializeBatteries();
magStripeReaderPanel1.SetupPointOfSale();
}
to this
private void Form1_Load(object sender, EventArgs e)
{
Thread infoThread = new Thread(new ThreadStart(unitInformationPanel1.PopulateUnitInformation));
infoThread.Start();
batteryInformationPanel1.InitializeBatteries();
magStripeReaderPanel1.SetupPointOfSale();
}
would the info thread be terminated when populate unit info is done? or would it be better to move that thread creation into PopulateUnitInformation? here is what it looks like.
public void PopulateUnitInformation()
{
unitModelLabel.Text = Properties.Settings.Default.UnitModelString;
serialNumberLabel.Text = Properties.Settings.Default.UnitSerialString;
biosVersionLabel.Text = UnitBios.GetBiosNumber();
osLabel.Text = OS.getOSString();
cpuLabel.Text = UnitCpu.GetCpuInfo();
var hdd = HddInfo.GetHddInfo();
diskNameLabel.Text = hdd.Name;
diskCapacityLabel.Text = hdd.Capacity;
diskFirmwareLabel.Text = hdd.Firmware;
memoryLabel.Text = MemoryInformation.GetTotalMemory();
NetworkPresenceInformation.GetAdapatersPresent();
biometricLabel.Text = BiometricInformation.IsPresent ? "Present" : "Not Present";
var networkAdaptersPresense = NetworkPresenceInformation.GetAdapatersPresent();
bluetoothLabel.Text = networkAdaptersPresense[0] ? "Present" : "Not Present";
wifiLabel.Text = networkAdaptersPresense[1] ? "Present" : "Not Present";
cellularLabel.Text = networkAdaptersPresense[2] ? "Present" : "Not Present";
}
--
wow i just ran it with the infothread and it still took some time to load (might be the 12 panels i created in the main thread. but it loaded the 12 frames and the unit information panel populated its information after everything loaded. That was cool, but is it safe? is it somewhat easy to make 12 threads for my panels? or is that dumb?
EDIT
this is what i did for stopwatch.
Stopwatch programTimer;
public Form1()
{
programTimer = Stopwatch.StartNew();
InitializeComponent();
SetupDebugWindow();
TerminateKeymon();
UnitModel.SetModel();
UnitSerialNumber.SetSerialNumber();
}
private void Form1_Shown(object sender, EventArgs e)
{
audioBrightnessPanel1.UpdateBrightnessTrackbar();
applicationLauncherPanel1.LoadApplications();
programTimer.Stop();
Console.WriteLine("Load Time: {0}",programTimer.ElapsedMilliseconds);
timer1.Start();
}
Will this be accurate?
EDIT 2 6/18/2012
Well I took the advice of using backgroundworker. Please let me know if i did this right.
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
unitInformationPanel1.PopulateUnitInformation();
batteryInformationPanel1.InitializeBatteries();
magStripeReaderPanel1.SetupPointOfSale();
}
You've asked a very broad question, but I'm going to give some general advice. If you want more specific information, you should consider deleting this question and posting more specific individual questions.
First and foremost, you should very strongly consider using something like the System.Threading.Task class for your multithreaded operations. There is a ton of information online about how to get started with it and how you can use Tasks to manage asynchronous operations. The short story is that if you're spinning up your own thread (as you're doing above), you almost certainly should be using something else to do that for you.
Adding multithreading to your code will not, in the strictest sense of the word, make it any "faster"; they will always take the same amount of total processor time. What it can and will do is two things: free up the UI thread to be responsive and allow you to split that "total processor time" across multiple cores or processors, should those be available to the system. So, if you have operation X that takes 10 seconds to complete, then just shifting operation X to another thread will not make it complete any faster than 10 seconds.
No, what you are doing above is not safe. I'm assuming that somewhere you've turned off checking for cross-thread communication errors in your app? Otherwise, that code should throw an exception, assuming this is a WinForms or WPF application. This is one reason to use Tasks, as you can easily separate the part of your process that actually takes a long time (or isn't UI related), then add a task continuation that uses the results and populates the UI elements within a properly synchronized context.
So my final approach this was as follows. I felt that my Main Form was doing more than it should. Sticking with the single responsibility principle I decided that MainForm should only be responsible for one thing, showing and displaying all 12 panels (now down to 11, i turned one into a menu item). So moved all the multithreading out of mainform and into program.cs. I found that this was even a little more difficult. What I did find though was a simple solution that allows me to not even worry about multithreading at all. It was the Idle event. Here is what i chose to do.
[STAThread]
static void Main()
{
DateTime current = DateTime.Now;
DateTime today = new DateTime(2012,7,19);
TimeSpan span = current.Subtract(today);
if (span.Days<0)
{
MessageBox.Show("Please adjust Time then restart Aspects","Adjust Time");
Process.Start("timedate.cpl").WaitForExit();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Idle += new EventHandler(Application_Idle);
mainForm = new MainForm();
mainForm.Closing += new CancelEventHandler(mainForm_Closing);
#if !DEBUG
TerminateKeymon();
StartSerial();
SetupDefaultValues();
EmbeddedMessageBox(0);
#endif
Application.Run(mainForm);
}
}
static void Application_Idle(object sender, EventArgs e)
{
Application.Idle -= Application_Idle;
mainForm.toolStripProgressBar1.Increment(1);
UnitInformation.SetupUnitInformation();
mainForm.toolStripProgressBar1.Increment(1);
Aspects.Unit.HddInfo.GetHddInfo();
mainForm.toolStripProgressBar1.Increment(1);
for (int i = 0; i < mainForm.Controls.Count; i++)
{
if (mainForm.Controls[i] is AbstractSuperPanel)
{
try
{
var startMe = mainForm.Controls[i] as AbstractSuperPanel;
startMe.StartWorking();
mainForm.toolStripProgressBar1.Increment(1);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + mainForm.Controls[i].ToString());
}
}
}
mainForm.toolStripProgressBar1.Value = 0;
}
to sum up what that does is is I add a idle listener event. Once the thead goes idle (basically meaning that Mainform is finished drawing and making all 12 panels and is showing on my desktop) I then kill the idle event listener and tell all my panels and classes to start working one at a time, updating my progress bar as I go. It works great. The load time is still the same as it was before, but there is window visibile after only a few seconds. Maybe not the best use of resources, but i think the solution is simple and straight forward.
I had a question somewhat related to this for Mobile app development a few months back (see How to write a Trigger?), and Marc "the man" Gravell posted back with a simple class that I modified to return data to my main application whenever the thread was complete.
The actual class I put into use has loads of pointless data (for you), so I'm going to paste in a revised version of Mr. Gravell's code using techniques which I used to make them work:
First, I had to create my own EventArgs class:
public class SuperEventArgs : EventArgs {
private object data;
public SuperEventArgs(object data) : base() {
this.data = data;
}
public object Data { get { return data; } }
}
Using that, here is a class I created to pass my data back to the main thread:
public delegate event DataChangedHandler(object sender, SuperEventArgs e);
public class Simple1 {
private object parameter1, parameter2;
private Control parent;
#if PocketPC
public delegate void MethodInvoker(); // include this if it is not defined
#endif
public Simple1(Control frmControl, object param1, object param2) {
parent = frmControl;
parameter1 = param1;
parameter2 = param2;
}
public event DataChangedHandler DataChanged;
public void Start() {
object myData = new object(); // whatever this is. DataTable?
try {
// long routine code goes here
} finally {
if (DataChanged != null) {
SuperEventArgs e = new SuperEventArgs(myData);
MethodInvoker methInvoker = delegate {
DataChanged(this, e);
};
try {
parent.BeginInvoke(methInvoker);
} catch (Exception err) {
Log(err); // something you'd write
}
}
}
}
}
Back in the actual main thread of execution, you'd do something like this:
public partial class Form1 : Form {
private Simple1 simple;
public Form1() {
object query = new object(); // something you want to pass in
simple = new Simple1(this, query, DateTime.Now);
simple.DataChanged += new DataChangedHandler(simple1_DataChanged);
Thread thread = new Thread(simpleStart);
thread.Start();
}
private void simpleStart() {
if (simple != null) {
simple.Start();
}
}
private void simple1_DataChanged(object sender, SuperEventArgs e) {
MyFancyData fancy = e.Data as MyFancyData;
if (fancy != null) {
// populate your form with the data you received.
}
}
}
I know it looks long, but it works really well!
This is not anything I have actually tested, of course, because there isn't any data. If you get to working with it and you experience any issues, let me know and I'll happily help you work through them.
~JoeP