MessageBox and while loop C# - c#

I'm modifying existing C# code in order to pilote a piston. Every 30ms, I have a direct feedback of the position of this piston, through an event. The value is stored in a global variable I use to get the current position of the piston.
What I'm trying to achieve: for a given distance input (A->C), I want the piston to travel at full speed for 95% of the distance (A->B), and then slower for the remaining 5% (B->C).
I have access to a command that defines the speed and the destination of the piston : pos(velocity, destination).
However, if I write that code:
pos(fullSpeed,B);
pos(reducedSpeed, C);
the piston directly goes from fullSpeed to reducedSpeed
I tried to use a while loop to compare the current position of the piston with the goal destination, however, upon entering the while loop, the variable storing the piston position does not update anymore.
However, I noticed that by throwing a MessageBox in between, the position value keeps on getting updated, and I can simply click "ok" to launch the second command.
pos(fullSpeed,B);
MessageBox.show("Wait");
pos(reducedSpeed, C);
I would like to know why the "while" loop stops the update of the position variable but the MessageBox does not. I mean, as long as I don't click the "ok" button, the box is here preventing me from doing anything, which for me ressembles a while loop behaviour. Is there another way for me to do this instead of the MessageBox ?
I have little to no knowledge when it comes to C# and no support. I have tried to look in the documentation, but I did not find an answer (I have probably missed it). Any lead is more than welcome.
EDIT: I have no documentation for that code, and it is barely commented. Here is what I gathered (really hope it helps):
To move the piston, taht function is called:
MyEdc.Move.Pos(control, speed, destination, ref MyTan);
control simply define what we pilote (a distance or a load, it is an enum), and I have no idea what MyTan does. Only thing I know is that the MyEdc.Move.Pos returns an error code.
If I look at the definition of "pos", I am redirected to class
public DoPEmove Move;
containing among other things:
public DoPE.ERR Pos(DoPE.CTRL MoveCtrl, double Speed, double Destination, ref short Tan);
DoPE.ERR is also an type enum. However, I cannot reach the definition of a function named "Pos". Coud it be within the .dll included ?
The following is the code that allows me to access the position of the piston (without the global variables):
private int OnData(ref DoPE.OnData Data, object Parameter)
{
if (Data.DoPError == DoPE.ERR.NOERROR)
{
DoPE.Data Sample = Data.Data;
Int32 Time = Environment.TickCount;
if ((Time - LastTime) >= 300 /*ms*/)
{
LastTime = Time;
string text;
text = String.Format("{0}", Sample.Time.ToString("0.000"));
guiTime.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_S].ToString("0.000"));
guiPosition.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_F].ToString("0.000"));
guiLoad.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_E].ToString("0.000"));
guiExtension.Text = text;
}
}
return 0;
}
Which is called using
MyEdc.Eh.OnDataHdlr += new DoPE.OnDataHdlr(OnData);
I realise how little I know on how the soft operates, and how frustrating this is for you. If you think this is a lost cause, no problem, I'll try Timothy Jannace solution, and if it does not help me, I'll stick with the MessageBox solution. I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.

I tried to use a while loop to compare the current position of the
piston with the goal destination, however, upon entering the while
loop, the variable storing the piston position does not update
anymore.
While you are in the while loop, your app can no longer receive and process the feedback event.
One possible solution would be to use async/await like this:
private const int fullSpeed = 1;
private const int reducedSpeed = 2;
private int currentPistonPositon = 0; // global var updated by event as you described
private async void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
pos(fullSpeed, B);
await Task.Run(() =>
{ // pick one below?
// assumes that "B" and "currentPistonPosition" can actually be EXACTLY the same value
while (currentPistonPositon != B)
{
System.Threading.Thread.Sleep(25);
}
// if this isn't the case, then perhaps when it reaches a certain threshold distance?
while (Math.Abs(currentPistonPositon - B) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
pos(reducedSpeed, C);
}
Note the button1_Click method signature has been marked with async. The code will wait for the while loop inside the task to complete while still processing event messages because of the await. Only then will it move on to the second pos() call.
Thank you for your answer ! It works like a charm ! (good catch on the
EXACT value). I learnt a lot, and I am sure the async/await combo is
going to be very usefull in the future ! – MaximeS
If that worked well, then you might want to consider refactoring the code and making your own "goto position" method like this:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
GotoPosition(fullSpeed, B);
GotoPosition(reducedSpeed, C);
}
private async void GotoPosition(int speed, int position)
{
pos(speed, position);
await Task.Run(() =>
{
while (Math.Abs(currentPistonPositon - position) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
}
Readability would be greatly improved.
You could even get fancier and introduce a timeout concept into the while loop. Now your code could do something like below:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
if (GotoPosition(fullSpeed, B, TimeSpan.FromMilliseconds(750)).Result)
{
if (GotoPosition(reducedSpeed, C, TimeSpan.FromMilliseconds(1500)).Result)
{
// ... we successfully went to B at fullSpeed, then to C at reducedSpeed ...
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
private async Task<bool> GotoPosition(int speed, int position, TimeSpan timeOut)
{
pos(speed, position); // call the async API
// wait for the position to be reached, or the timeout to occur
bool success = true; // assume we have succeeded until proven otherwise
DateTime dt = DateTime.Now.Add(timeOut); // set our timeout DateTime in the future
await Task.Run(() =>
{
System.Threading.Thread.Sleep(50); // give the piston a chance to update maybe once before checking?
while (Math.Abs(currentPistonPositon - position) > 0.10) // see if the piston has reached our target position
{
if (DateTime.Now > dt) // did we move past our timeout DateTime?
{
success = false;
break;
}
System.Threading.Thread.Sleep(25); // very small sleep to reduce CPU usage
}
});
return success;
}

If you're using events you are probably having concurrency issues. Especially with events being raised every 30ms!
A very simple way to handle concurrency is to use a lock object to prevent different threads from using contested resources simultaneously:
class MyEventHandler
{
private object _lockObject;
MyEventHandler()
{
_lockObject = new object();
}
public int MyContestedResource { get; }
public void HandleEvent( object sender, MyEvent event )
{
lock ( _lockObject )
{
// do stuff with event here
MyContestedResource++;
}
}
}
Keep in mind that is very simple and by no means perfect in every scenario. If you provide more information about how the events are raised and what you're doing with them people will be able to provide more help.
EDIT:
Using that signature you posted for the Pos method I was able to find documentation on the library you are using: https://www.academia.edu/24938060/Do_PE
The reason you only see the method signature when you goto definition is because the library has been compiled into a dll. Actually, it probably wouldn't be that useful to see the code anyway because it looks like the library is a C# wrapper around native (c or c++) code.
Anyways, I hope the documentation is helpful to you. If you look at page 20 there are some pointers on doing movement. This is going to be a challenge for a new programmer but you can do it. I would suggest you avoid using the event handler to drive your logic and instead stick with using the synchronous versions of commands. Using the synchronous commands your code should operate the same way it reads.

I believe what you'll want to do is add a call to:
Application.DoEvents();
This will allow your application to process posted messages (events), which will allow that global variable to be updated.
I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
The reason that works is because you're giving the WndProc a chance to process events which have been sent to the application. It's not an intended feature of that call to MessageBox.Show();, but it is a consequence. You can do the same thing with a call to Application.DoEvents(); without the interruption of the message box.

Related

Is there a way to await a flag change in a function?

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.

Comparing to previous string gets me stuck in a loop

Ok, so I have a program that checks a twitch url for whenever someone new follows the channel by comparing a certain string is different from a "temp" string that I use for reference. But instead of only outputting a message every time the string is different it gets stuck in a loop of outputting the latest follower and then second latest follower then latest follower again etc.
What am I missing? Also, is there a better way of checking if a certain string is updated?
private void DonationListen()
{
try
{
followers = this.donationClient.DownloadString("https://api.twitch.tv/kraken/channels/" + channel.Trim() + "/follows");
donationTimer.Interval = 10000;
donationTimer.Elapsed += new ElapsedEventHandler(CheckUpdates);
donationTimer.Start();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void CheckUpdates(object source, ElapsedEventArgs e)
{
donationTimer.Stop();
int startIndex = followers.IndexOf("display_name\":") + 15;
int endIndex = followers.IndexOf(",\"logo", startIndex);
prevFollower = followers.Substring(startIndex, (endIndex - 1) - startIndex);
if (firstRun == true)
{
temp = prevFollower;
}
else if (prevFollower != temp)
{
//New follower detected
temp = prevFollower;
if (updateFollower != null)
{
updateFollower(prevFollower);
}
}
else
{
//Follower is the same as before
}
firstRun = false;
DonationListen();
}
I'm thinking it might have something to do with the downloadstring trying to get a new string from the url but failing since it's currently being updated and therefore the CheckUpdates doesn't have correct information or something?
Without a good code example, it is difficult to know for sure what the problem is. So we are left inspecting the code you did show us.
Based on that, it appears to me as though your "loop" is being caused by repeatedly subscribing to the same event.
In your DonationListen() method, you have this statement:
donationTimer.Elapsed += new ElapsedEventHandler(CheckUpdates);
In the CheckUpdates() method (i.e. the handler you are subscribing), you have this statement (as the very last statement):
DonationListen();
In other words, every time the timer's Elapsed event is raised, you add another event handler instance to the event. For every handler you add, the CheckUpdates() method will be called.
Again, without a good code example, it is difficult to know for sure what the best fix would be. But given the code that is here, it appears to me that you could just remove that last statement from the CheckUpdates() method, as the DonationListen() method does not appear to do anything that needs doing again.

this.Invoke(...) - is this bad practice?

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.

C# Continuously / uninterrupted reading data (from third party SDK)

Intro:
I am developing software that uses motion trackers to analyse human motor systems. Currently I am implementing hardware from xsens and using their SDK to receive data from their wireless sensors.
The SDK offers a COM interface with a "getData" method which you call to receive the currently available xyz axis data (simplified). If you do not call getData, you skip that "beat" so you will be missing data, there is no caching in their hardware/SDK.
Problem:
My problem is that I need to get data at a rate of at least 75Hz, preferably a bit more, but 75 would be acceptable, but I am currently quickly dropping to just 20 signals per second...
If I remove the processing bit (see the sample below) I get perfect sample rates, so I think either the dequeue is causing the enqueue to pause. Or the "heavy" CPU load is causing all threads to wait. I have no idea how to figure out what is actually causing it, the profiler (EQATEC) just shows my "GetData" method is taking longer after a while.
Question:
What is the best technique to use to accomplish this? Why would my "reading" thread be interrupted/blocked? There must be more cases where people need to read from something without being interrupted, but I have been Googleing for 2 weeks now and apparently I can't find the correct words.
Please advise.
Thanks
Simplified code sample, version 4, using a MultiMedia timer (http://www.codeproject.com/Articles/5501/The-Multimedia-Timer-for-the-NET-Framework) and a BackgroundWorker
public class Sample
{
private MultiMediaTimer _backgroundGetData;
private bool _backgroundGettingData;
private BackgroundWorker _backgroundProcessData;
private ConcurrentQueue<double> _acceleration = new ConcurrentQueue<double>();
private void StartProcess()
{
if (_backgroundGetData == null)
{
_backgroundGetData = new MultiMediaTimer {Period = 10, Resolution = 1, Mode = TimerMode.Periodic, SynchronizingObject = this};
_backgroundGetData.Tick += BackgroundGetDataOnTick;
}
_backgroundProcessData = new BackgroundWorker {WorkerReportsProgress = false, WorkerSupportsCancellation = true};
_backgroundProcessData.DoWork += BackgroundProcessDataOnDoWork;
_backgroundGetData.Start();
}
private void BackgroundProcessDataOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
double value;
if (!_acceleration.TryDequeue(out value)) value = 0;
//Do a lot of work with the values collected so far,
//this will take some time and I suspect it's the cause of the delays?
}
private void BackgroundGetDataOnTick(object sender, EventArgs eventArgs)
{
if (_backgroundGettingData) return;
_backgroundGettingData = true;
//123 represents a value I am reading from the sensors using the SDK
double value = 123;
if (value == -1)
{
Thread.Sleep(5);
continue;
}
_acceleration.Enqueue(value);
if (_acceleration.Count < 5) continue;
if (!_backgroundProcessData.IsBusy)
{
_backgroundProcessData.RunWorkerAsync();
}
_backgroundGettingData = false;
}
}
I am seeing the problem here
_backgroundProcessDataThread.Start();
while (!_backgroundProcessDataThread.IsAlive){}
_backgroundGetDataThread.Start();
while (!_backgroundGetDataThread.IsAlive) {}
Well, you can see here that you are having infinite loop here and the second thread starts only after first has finished its work. i.e. first thread is done. This is in no way an ideal model.
Sorry, I recognized the issue later.
The problem is, _backgroundGetDataThread will start only after _backgroundProcessDataThread has done its work.

Have MessageBox appear once (code inside timer)

UPDATE: I've managed to fix my problem. Using the code below, I moved my MessageBox AFTER my XML saving and changed the Timer from 100ms to 400ms. I now have 1 box appear, thank god. Although If anyone has a short cut to updating a single value (ActReminded) in the List array(ActListTask), that'd be great to know.
I'm having a little issue with displaying the MessageBox. Show inside a timer without it spamming me. Here's the part of the code I've been working with:
public class ActiveTasks
{
//Properties here
}
public List<ActiveTasks> ActTaskList = new List<ActiveTasks>();
for (int i = 0; i < ListActive.Items.Count; i++)
{
if (DTime.Date == newDateTime.Date)
{
if (newDateTimeLeft.CompareTo(TimeSpan.Zero) <= 0 && ActTaskList[i].ActReminded != "true")
{
MessageBox.Show("!!!!");
ActTaskList.Add(new ActiveTasks()
{
ActTitle = ActTaskList[i].ActTitle,
ActDesc = ActTaskList[i].ActDesc,
ActDate = ActTaskList[i].ActDate,
ActTime = ActTaskList[i].ActTime,
ActStatus = ActTaskList[i].ActStatus,
ActReminded = "true",
ActRepeat = ActTaskList[i].ActRepeat
});
ListActive.Items.RemoveAt(i);
ActTaskList.RemoveAt(i);
XDocument XmlActTasks = GenerateActiveListToXML(ActTaskList);
}
}
}
I actually decided I may want to hold onto the reminder status, whether it has been shown or not as I wouldn't want a repeated reminder every time the program is opened. Since I don't know of a way to update an individual part of ActTaskList I just re-added it, and then deleted the original. This code manages to recognise that if it happens, it will change the reminder status from false, to true; after I've Ok'ed all the spam. So it will stop the MessageBox once I've managed to closed all the Messageboxes. However, it doesn't stop the spam. Would it be anything to do with the fact I've set the timer to 100ms? Or could their be an alternative way to make the messagebox appear without it being inside the timer?
The odds of the current time lining up exactly to the second what is happening in your loop is small. Why not treat newDateTime as a cut off point and just set a flag?
//Declare this outside of the loop
bool hasDisplayed = false;
//Inside the timer event handler
if (!hasDisplayed && DateTime.Now >= newDateTime)
{
hasDisplayed = true;
MessageBox.Show("!!!!!!!!!!!!!");
}
Can you do something like this?
Action message = () => MessageBox.Show("!!!!!!!!!!!!!"));
object lockOb = new object();
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
lock(lockOb)
if(null != message)
{
message();
message = null;
}
}
You say you've already tried a boolean indicating the message has already been shown, I'm assuming because the code probably looked like it did below.
void TimerLoop()
{
bool msgAlreadyShown;
if(!msgAlreadyShown)
{
MessageBox.Show("!!!!!!!");
}
// Other work in your timer function
}
The problem with that code is that the bool will be set to false each time the function is called by the timer. You haven't posted much code, but you've at least stated what you're trying to accomplish, a timer that checks if a reminder should be presented to the user.
I'm about to make some wild guesses about how you've put together your software, there's a good chance it's way off, but I hope it might point you in the right direction. You could have some sort of reminder class like this:
public class Reminder
{
string Message { get; set;}
DateTime Alarm { get; set; }
bool IsDismissed { get; set; }
}
I'm assuming you might want to have multiple reminders that can be checked for in the timer loop, so your timer loop could look something like:
private List<Reminder> _activeReminders; // A list of reminders
void TimerLoop(object s, ElapsedEventArgs e)
{
lock(_activeReminders)
{
var now = DateTime.Now;
foreach(var reminder in _activeReminders)
{
// only run this code if the time has passed and it hasn't already
// been shown
if(now.CompareTo(reminder.Alarm) >= 0 && !reminder.IsDismissed)
{
MessageBox.Show(reminder.Message);
reminder.IsDismissed = true;
}
}
}
}
This is a pretty naive implementation, since you probably don't want to hold onto the reminders for forever and the reminders are never removed from the _activeReminders list, but you essentially just need to add some sort of state to determine if the reminder has already been shown.
Of course, this isn't a complete example either, since I never new up the _activeReminders field or add anything to it, but I think this might help get the idea of what you need to do across. Also, you might not care about multiple reminders, and your timer code could look nothing like this. The main idea was to show you how you can keep track of the state of a reminder, and tailor it to your own code. The above was just an example.
Also, I haven't actually tested it, so treat it more like pseudocode than anything else. However, the logic is sound, and should it should only cause the message box to appear once.

Categories