how to use a long running process in winforms c# - c#

I am using a background for my sms application.
I have created an application which needs to send messages continously.
When i use background.My application gets hanged i dont know why it is,
my code is
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//mycode
}
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
backgroundWorker1.CancelAsync();
backgroundWorker1.RunworkAsync();
}
later i have tried this
public void Thread()
{
Thread D = new Thread(BackgroundCode);
D.Start();
}
public void BackgroundCode()
{
for (int i5 = 1; i5 > 0; i5 += 1)
{
//mycode
}
}
this two works fine for 2 or 3 min but after that it gets hang.
Please can anyone please help me.
Thanks In Advance.

try this
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(true)
{
//your sms code
//call CancelAsync() here if you want to get out!!!!
}
}
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
//donot include RunWorkerAsync() and CancelAsync() in this method!
}

This is a bit of a long post, but it seems to fit your problem quite well.
Basically, it shows how you can do this with a BackgroundWorker or the Task Parallel Library (TPL would be my suggestion)
For the TPL you create a ProgressReporter class that will be used in the class to pass messages back to the main thread, while continuing to run the task.
Also, your for loop will never end because it is saying to run while i5 is greater than 0. And, it starts at 1 and counts up, so it will never be less than or equal to zero. That will fix your hanging, but once you fix that, the progress reporter from the blog class should help with the rest.

Related

C# Keithley IVI Measure is slow

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!

how to include mutliple threading in this script

I am working on a project which includes two main processing, I have tried using timer_tick to handle the processing which makes the application really slow. The application needs to be running at all times, I wanted the timer aspect of the timer_tick to trigger the methods every X seconds but with the multiple threading, as this makes it a lot faster.
Can anyone help?
The current structure of the application is below:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
setting_info();
}
public void setting_info()
{
// takes data from config file for API connections
}
private void swis()
{
// connects to API and fetches data
// need to be continuously running - Ideally Interval(1200)
}
private void st_processing()
{
// processes the data that was fetched in swis() slows down the program without multiple threading
// need to be continuously running - Ideally Interval(800)
}
private void alert_in_timer_Tick(object sender, EventArgs e)
{
while (alert_in == true)
{
swis();
break;
}
}
private void st_processing_timer_Tick(object sender, EventArgs e)
{
while (st_processing == true && alert_data_database_has_data == true)
{
st_processing();
//check_error_count();
alert_data_database_has_data = false;
break;
}
}
}
It's not clear what you want to know. There are many good threading tutorials for C# as discussed here for example this one
Starting a thread is easy
Thread worker = new Thread(new ThreadStart(swis));
//...
worker.join();
You will need to be careful if you need to update the GUI as a result of what the thread does. Previously discussed here.
At the moment you break from the alert_in_timer_Tick once it's called the swis function.
while (alert_in == true)
{
swis();
break;// why is this here?
}

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();

C# do while loop start stop

I am trying to make a stop button for this loop but it runs indefinite, nothing happens when i click button 2
bool dowhile = false;
private void button1_Click(object sender, EventArgs e)
{
do
{
for (int i = listbox1.Items.Count - 1; i >= 0; i--)
{
string textstring = listbox1.Items[i].ToString();
richTextBox1.AppendText("" + textstring + ": Done\n");
Thread.Sleep(1000);
}
} while (!dowhile);
}
private void button2_Click(object sender, EventArgs e)
{
this.dowhile = true;
}
where do i go wrong ?
sry for the "lvlchanger" typo, code is ok now, nothing missing
i'm also looking for a not-so-long fix on this :))
The system can't process anything from the message queue (i.e. button clicks, repaints, etc) until your button1_Click completes - which it never will. This is exactly what causes all those "{blah} is not responding" messages - code that doesn't respond to the message queue promptly.
Basically, don't do that. A hacky fix would be some DoEvents(), but NO! do it properly; basically, handle the event from button2_Click instead. Perhaps you should run the refreshes from a timer tick?
Thread.Sleep is almost always the incorrect approach; when you find yourself wanting to use something like it or Application.DoEvents in your code, it's time to take a long step back and think about what you're really doing and why it isn't working. A new design should be in your future.
The real problem here is that you're doing work on the UI thread, which blocks the user from interacting with your application. Your click on Button2 is getting recognized and processed after the loop has already finished processing, at which point it does absolutely nothing.
This is because threads can only complete one task at a time. And, in fact, Thread.Sleep(100) only makes this worse, because it forces the thread to spin and do nothing for 100 milliseconds. That's 100 more milliseconds it will take for the loop to complete for absolutely no gain.
The correct solution to this (common) problem is to spin the loop off onto a separate thread, using something like the BackgroundWorker class. The MSDN entry has a very good example of its use, including your specific use case: allowing the user to cancel a long-running background task.
private void button1_Click(object sender, EventArgs e)
{
bool dowhile = false;private void button1_Click(object sender, EventArgs e){
do
{
for (int i = listbox1.Items.Count - 1; i >= 0; i--)
{
string textstring =listbox1.Items[i].ToString();
richTextBox1.AppendText("" + textstring + ":` `Done\n");
Thread.Sleep(1000);
}
} while (!lvlchanger && dowhile == false);
}
private void button2_Click(object sender, EventArgs e)
{
this.dowhile = true;
}
Add an Application.DoEvents() to the loop to allow the application to process events from other sources.
/EDIT
This should work, but...
"This is almost never the correct answer" - Cody Gray

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