C# Keithley IVI Measure is slow - c#

I'm using the Keithley 2100 digital multimeter to gather VAC readings for a piece of calibration software i'm writting. I've made a small test program to gather some data on Keithley's IVI Class Library that can be downloaded from their website.
I'm running a background worker which is gathering outputs from the multimeter, see code;
private void readButton_Click(object sender, EventArgs e) // gather readings
{
if (!backgroundWorker1.IsBusy)
{
address = Ke2100FunctionEnum.Ke2100FunctionACVolts;
range = Double.Parse(textBox2.Text);
resolution = Double.Parse(textBox3.Text);
backgroundWorker1.RunWorkerAsync();
}
else
{
MessageBox.Show("Task already enabled");
}
}
This is my gather reading button, it checks to make sure the background worker isn't busy, then runs the worker.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
Invoke(new Action(() =>
{
ACResult = ke2100Device.Measure(address, range, resolution);
richTextBox1.Text += ACResult.ToString() + "\n";
}));
if(backgroundWorker1.CancellationPending)
{
backgroundWorker1.Dispose();
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
It takes around a second for the ke2100Device.Measure function to process one reading, but in this time period the whole program becomes unresponsive, which I just can't have in my program. I've loaded up the task manager to see if any of my cores are on 100%, as it seems like quite an intensive function, but my usage is just fine.
I'm a little stumped on how to get fix this issue. I've commented out the ke2100Device.Measure function and just had the rich text box add random numbers, this works as expected with no unresponsiveness.
The only ideas I have just seem to be another way of doing the same thing... Coffee break!
-- Edit --
Updated code;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
ACResult = ke2100Device.Measure(address, range, resolution);
Invoke(new Action(() => { richTextBox1.Text += ACResult.ToString() + "\n"; }));
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
Though if I run this debug code to check my bgw;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
//ACResult = ke2100Device.Measure(address, range, resolution);
Invoke(new Action(() => { richTextBox1.Text += 0 + "\n"; })); //ACResult.ToString()
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
Then I don't get any hangs, perhaps there is an actual issue with the Measure function? Could it be doing something I'm not fully realising or seeing?

The call to Measure should be outside of the Invoke action. Calling it inside the Invoke effectively runs it on the UI thread, rendering your background worker meaningless.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
ACResult = ke2100Device.Measure(address, range, resolution);
Invoke(new Action(() => { richTextBox1.Text += ACResult.ToString() + "\n"; }));
if(backgroundWorker1.CancellationPending)
{
//backgroundWorker1.Dispose(); // I don't think you want this here!
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}

http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
As you want to notify of the state on each measure you probably want to use the the ProgressChanged() event that the BackgroundWorker exposes. You can set the UserState property when you call ReportProgress().
Doing this will mean you don't have to think about whether to call Invoke() or not as the BackgroundWorker will hide this implementation detail for you.
Also, if you update your GUI every 10ms i.e. 100 times per second you user probably won't be able to notice the different updates. You might want to change this value to be configurable and then play with it to get the desired refresh rate.

I have found the issue. I went straight into the basics of how the device communicates with my laptop, and found out that it uses SCPI commands, so from this point I started making two really simple functions that creates a connection, and then sends a command to the multimeter.
After this point I realised that all commands being sent to the multimeter and back are done on the command line, which then lead me to believe that the command line and GUI thread are actually the same thread, which would explain why the whole program would hang when trying to read data from my device.
How did I fix this? Easily, I put my app on another thread before loading it up, see code!
Thread applicationThread = new Thread(() => Application.Run(new Form1()));
applicationThread.Start();
No more hanging! I hope this can help other people down the line. Thanks for the help guys and girls!

Related

c# Make a delayer but still be able to have form open

and on my c# program whenever i try:
System.Threading.Thread.Sleep(#);
as in delay number
It works, but whenever its "delaying" (i guess that's what its called) I can't get my form to pop up on my screen from the task bar, almost like reopening it (?). Could somebody help me make a thread that doesn't "freeze" the form? Thanks!
So, yeah, I have already tried
System.Threading.Thread.Sleep(#);
But that just freezes the form :/ thank you
oh btw, this is c#
You can use a Timer to delay a operation.
Example:
Timer timer = new Timer(10000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Start();
After 10000 MS the following Method will be called:
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//DoSomething
}
Sounds like you're after a background worker. This will allow you to keep your main form up but do some time consuming processing on another thread. Since you didn't post any specific code for your issue, I'm pasting in a snippet from a larger example found on MSDN
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}

How to handle this asynchronous programming scenario in C#

I just had an interview 5 minutes back. I was given this scenario and he asked me the question on how to handle this in C# 1.0 or 2.0. He said there is a basic feature to handle this, I wasn't sure. Can somebody please help :(
Question:
There are 2 text boxes in Winform application and a button. One text box takes input value and when button is clicked, it process input in server which takes hell lot of time and finally displays the result in another textbox. As it takes very long time in server, the UI shouldn't be interupted, how do you handle this scenario he asked me :(
Answer I gave:
I told multithreading and said about async and await. He was expecting a simple way of handling this in C# 2.0 thing. I was guessing about asynchronous delegates. He wasn't convinced. Please someone explain me with little understandble code :)
You would run the long running process in a separate thread to the UI to prevent it hanging, perhaps a BackgroundWorker would be used for example: -
bgWorker.RunWorkerAsync([DATA TO PROCESS])//Passing in data to operate on
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
MyObject obj = (MyObject)sender;
//
// Do some work with the data on the server
//
// Report on progess, is it done?
bgWorker.ReportProgress();
}
You could also have a work complete method
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Work is complete, notify user
}
You could also use a ThreadPool, which requires a little more set up but i find is more flexible. For example: -
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), [DATA TO PROCESS]);
Interlocked.Increment(ref workItems);
workItems would be a count of the number of items left to process, this could be used to keep track of whether the task is complete or not. We then define a DoWork method where we process the data and decrement our workItems counter. Once an item has been processed, we report progress via delegates such as: -
private delegate void ThreadDone(MyObject obj);
private delegate void TaskDone();
public void DoWork(object sender)
{
MyObject obj = (MyObject)sender;
this.Invoke(new ThreadDone(ReportProgress), result);
Interlocked.Decrement(ref workItems);
if (workItems == 0)
{
this.Invoke(new TaskDone(WorkComplete));
}
}
Report progress might look like this: -
private void ReportProgress(MyObject obj)
{
if (workItems >= 0)
{
//Job isn't complete, report progress
}
}
private void WorkComplete()
{
}
In .Net 2 winform applications, the simplest solution is to use a BackgroundWorker. Its events are raised on the UI thread so you don't need to do any marshalling yourself.
The usual pattern looks like:
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += delegate(object sender, DoWorkEventArgs e) {
try {
e.Result = server.LongRunningOperation();
}
catch(Exception ex) {
e.Error = ex;
}
};
bg.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
//update UI
};
bg.RunWorkerAsync();

Button Text, Inconsistent

Why does my first attempt to change a button's text in this code not work, while the third attempt does work ?
My user will have to wait a few seconds while the serial port connects. After that, I want to alert him that he has already connected (a second attempt can cause problems).
I wanted to let him know that things are okay, so he won't think "duh" and click twice.
Fail. The text change never appears.
Okay, why does the third change in button text work, but the first one does not ? I don't know if the second one works or not.
/***********************************************************************
* Button: Connect Port *
***********************************************************************/
private void TheConnectPortButton_Click(object sender, EventArgs e)
{
string OldText = TheConnectPortButton.Text;
TheConnectPortButton.Text = "Busy, Please Wait"; /////// This never happens
ButtonBoss.ButtonHandler_ConnectPort();
TheConnectPortButton.Text = OldText; /////// Not sure if this happens
if (aUartSemaphoreThatTells.IfWeHaveConnectedToAPort == (int)aValueWhichIndicatesThat.YesWeHaveAGoodPortConnected)
{
TheConnectPortButton.Text = "Connected"; /////// This one does happen
}
}
the aUartSemaphoreThatTells.IfWeHaveConnectedToAPort is also used by the ButtonBoss routine to make sure he doesn't connect a second time, along with other button routines (e.g., make sure we are connected before we Tx/Rx or whatever).
I tried changing the code after the routine returns to look like this...
if (aUartSemaphoreThatTells.IfWeHaveConnectedToAPort == (int)aValueWhichIndicatesThat.YesWeHaveAGoodPortConnected)
{
TheConnectPortButton.Text = "Connected";
}
else
{
TheConnectPortButton.Text = OldText;
}
...and I still get the same result.
My guess (and that's all it is) is that threading is somehow involved in all this, and that the serial port routines trump the button text changing routines by some convolution that I don't follow properly at the moment.
Question: What do I need to do to get the text to change before the connection stuff hogs the system ?
(If that's what's happening)
Question 2: If I can't make this happen, I think I've read about "greying out" the buttons, or, I believe I saw somewhere that I can actually make a button go away right before the user's eyes so that he can't click it again. Links to example code would be welcome.
The problem is you're doing everything from one and the same event-handler consequently, so that the button has no time to get updated (redrawn). You could call Application.DoEvents(); method, but it's not a good idea at all, please, read Use of Application.DoEvents()
I think usually you're expected to push a time-consuming task into a separate thread, get progress report from it and update your GUI. There is a plenty of ways to create a "worker" thread and get some respond from it. For example, use a BackgroundWorker Class:
public partial class Form1 : Form
{
public Form1() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker w = new BackgroundWorker();
w.WorkerReportsProgress = true;
w.DoWork += new DoWorkEventHandler(w_DoWork);
w.ProgressChanged += new ProgressChangedEventHandler(w_ProgressChanged);
w.RunWorkerCompleted += new RunWorkerCompletedEventHandler(w_RunWorkerCompleted);
w.RunWorkerAsync();
button1.Text = "Started";
}
//may influence GUI, as this event handler is run on the GUI thread
void w_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Text = "Job is done";
}
//may influence GUI, as this event handler is run on the GUI thread
void w_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
button1.Text = e.ProgressPercentage.ToString();
}
//runs in the worker thread...should do the actual job
//may influence GUI through `ReportProgress`
//or through `Invoke` method
void w_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(500);
worker.ReportProgress(10 * i);
}
}
}
Or you may use Task Class:
public partial class Form1 : Form
{
public Form1() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e)
{
new Task(DoTask).Start();
}
void DoTask()
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(500);
//here you need to update GUI through `Invoke` method
//as the GUI may only be influenced from the the thread,
//where it's created
this.Invoke(new Action<int>((j) =>
{
button1.Text = j.ToString();
}), 10 * i);
}
}
}

Program doesn't increment progress bar while waiting for thread to exit

I have a c# form app that serves as an UI and executes an external exe. I want to make a progress bar increment until the external exe finishes executing. so i have the following code:
// create thread and Start external process
Thread MyNewThread = new Thread(new ThreadStart(startmodule));
MyNewThread.Start();
do
{
if (progressBar1.Value < 100)
{
progressBar1.Value++;
}
} while (MyNewThread.IsAlive);
label5.Text = "Status: Done";
// startmodule()
void startmodule()
{
ProcessObj = new Process();
ProcessObj.StartInfo.FileName = ApplicationPath;
ProcessObj.StartInfo.Arguments = ApplicationArguments;
ProcessObj.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
ProcessObj.Start();
}
Instead it fills the bar up instantly and shows "Done" message but the external exe (AppPath) still runs in the background.
Please post some ideas im stuck. i don't know whats wrong. Thank you for your time.
You cannot make this work, you cannot guess how long the process will take. Set the ProgressBar.Style property to Marquee. Set it Visible property to true when you start the process. Use the Process.Exited event to set it back to false. Like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = false;
}
private void ButtonRunProcess_Click(object sender, EventArgs e) {
var ProcessObj = new Process();
ProcessObj.SynchronizingObject = this;
ProcessObj.EnableRaisingEvents = true;
ProcessObj.Exited += new EventHandler(ProcessObj_Exited);
ProcessObj.StartInfo.FileName = #"c:\windows\notepad.exe";
// etc...
ProcessObj.Start();
progressBar1.Visible = true;
}
void ProcessObj_Exited(object sender, EventArgs e) {
progressBar1.Visible = false;
}
}
Well the loop is being run so fast, that it reaches 100% before your task is actually completed. The condition that the loop is being check for (The thread being alive) is going to be true until your task is completed, but the loop is causing the progress bar to fill up prematurely.
In order to run a progress bar you have to be able to quantify the progress of the long running task. You have nothing in the code that attempts to quantify this.
You would need there to be communication between the two processes in order to make this progress bar work well. In other words the external process needs to send messages back to the parent app informing the parent app of the measure of progress. Now, that can be hard to achieve so a marquee style progress bar may be more appropriate.
Finally i got some "free" time to test the backgroundworker as suggested above. i can say it's the best solution and it doesn't freeze the UI. Example implementation follows:
preparemodule()
{
ProcessObj = new Process();
ProcessObj.StartInfo.FileName = ApplicationPath;
ProcessObj.StartInfo.Arguments = ApplicationArguments;
}
void run_Click(object sender, EventArgs e)
{
preparemodule();
backgroundWorker1.RunWorkerAsync(ProcessObj);
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int i=0;
ProcessObj.Start();
while (checkifexists("notepad", 0) == true)
{
i++;
label5.Text = "Status: notepad running... " + progressBar1.Value.ToString() + "%";
Thread.Sleep(3000);
backgroundWorker1.ReportProgress(i);
if ((backgroundWorker1.CancellationPending == true))
{
e.Cancel = true;
}
}
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage <= 100)
{
progressBar1.Value = e.ProgressPercentage;
}
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label5.Text = "Status: Done";
}
void cancel_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
As you see we can even cancel it. and by checking if notepad is running we can increment out progressbar. Dont forget to enable bgWorker's "reportsprogress" and "supportscancellation" properties somewhere in your code. i hope it helps someone.
First, #Tim answer is right about what is happening.
If you can control the external app, make a way to it communicate with the main process telling the current state and update the progress bar according to these messages.
If is not possible, try to estimate the execution time and set the progress according to the execution time. This is valid if it performs always in same time for the same task.
Background worker thread was designed for this sort of thing.
It has an event you can fire while processing something, you handle it and update your progress bar. Course as noted by others you don't seem to have any measure of progress, just some time has passed, so it's not really an indication of progress you want but some sort of "I'm busy" animation, if you use a progress bar for that you get all sorts of issues that drive the UI boys mad, like it never gets to 100%, or it gets to 100% well before the operation has finished, or even cycles round.
So if you can indicate some progress from the thread, e.g if you are looping through X items fire the progress event every 10% of X. Use a Background worker thread.
If you can't don't use a progress bar kick the thread off an make some animated control visible. When the thread finishes make the animation invisible again. What and how of the animation is up to you and your UI boys.

Restart background worker

Is there a way to directly "restart" a background worker?
Calling CancelAsync() followed by RunWorkerAsync() clearly won't do it as their names imply.
Background info:
I have a background worker which calculates a total in my .net 2.0 Windows Forms app.
Whenever the user modifies any value which is part of this total I'd like to restart the background worker in case it would be running so that directly the latest values are considered.
The backgriound work itself does not do any cancleing.
When you call bgw.CancelAsync it sets a flag on the background worker that you need to check yourself in the DoWork handler.
something like:
bool _restart = false;
private void button1_Click(object sender, EventArgs e)
{
bgw.CancelAsync();
_restart = true;
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 300; i++)
{
if (bgw.CancellationPending)
{
break;
}
//time consuming calculation
}
}
private void bgw_WorkComplete(object sender, eventargs e) //no ide to hand not sure on name/args
{
if (_restart)
{
bgw.RunWorkerAsync();
_restart = false;
}
}
There are a couple of options, it all depends on how you want to skin this cat:
If you want to continue to use BackgroundWorker, then you need to respect the model that has been established, that is, one of "progress sensitivity". The stuff inside DoWork is clearly required to always be aware of whether or not the a pending cancellation is due (i.e., there needs to be a certain amount of polling taking place in your DoWork loop).
If your calculation code is monolithic and you don't want to mess with it, then don't use BackgroundWorker, but rather fire up your own thread--this way you can forcefully kill it if needs be.
You can hook the change event handler for the controls in which the values are changed and do the following in the handler:
if(!bgWrkr.IsBusy)
//start worker
else if(!bgWrkr.CancellationPending)
bgWrkr.CancelAsync();
Hope it helps you!
I want to leave my requests running, but no longer care about the results. I override the value of the background worker (my busy spinner is using the isBusy flag).
private void SearchWorkerCreate() {
this.searchWorker = new BackgroundWorker();
this.searchWorker.DoWork += this.SearchWorkerWork;
this.searchWorker.RunWorkerCompleted += this.SearchWorkerFinish;
}
private void SearchWorkerStart(string criteria){
if(this.searchWorker.IsBusy){
this.SearchWorkerCreate();
}
this.searchWorker.RunWorkerAsync(criteria);
this.OnPropertyChanged(() => this.IsBusy);
this.OnPropertyChanged(() => this.IsIdle);
}
May this method help someone... I've created a function to reset the backgroundworker in one method. I use it for task to do periodically.
By creating a Task, the backgroundworker is can be stopped with the CancelAsync and restarted inside the Task. Not making a Task wil start the backgroundworker again before it is cancelled, as the OP describes.
The only requirement is that your code runs through some loop, which checks the CancellationPending every period of time (CheckPerMilliseconds).
private void ResetBackgroundWorker()
{
backgroundWorker.CancelAsync();
Task taskStart = Task.Run(() =>
{
Thread.Sleep(CheckPerMilliseconds);
backgroundWorker.RunWorkerAsync();
});
}
Inside the backgroundworker I use a for-loop that checks the CancellationPending.
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while(true)
{
if (backgroundWorker.CancellationPending)
{
return;
}
//Do something you want to do periodically.
for (int i = 0; i < minutesToDoTask * 60; i++)
{
if (backgroundWorker.CancellationPending)
{
return;
}
Thread.Sleep(CheckPerMilliseconds);
}
}
}

Categories

Resources