|
-
Mar 20th, 2011, 05:01 AM
#1
Thread Starter
Hyperactive Member
Wait for Backgroundworker to finish
How can I wait for a backgroundWorker to finish and still be in the same void?
For example:
I send a list with files to process to a void, DoThem(list).
Then in that void, if the file is a txt, send it to backgroundworker1. If the file is a jpg send it to backgroundworker2.
But I only want one backgroundworker to run at the same time (reporting progress to the same progressbar).
I know the bw has a bwFinished event, but if I need to use that I would need to do a hell of a more programming that looks quite ugly to me (passing a parameter with what to do when finished blablabla).
What I have read you can use the WaitOne thingy. But it locks the UI and I want to be able to change the progressbar all the time.
Last edited by Cyb3rH4Xter; Mar 20th, 2011 at 05:12 AM.
-
Mar 20th, 2011, 08:57 AM
#2
Re: Wait for Backgroundworker to finish
There's no such thing as "a void". It's a function, with a return type of void, i.e. it doesn't return anything at all.
What's the point of using a BackgroundWorker at all if you're going to wait for it to finish? You may as well just do the work right there in the same function. The point of using the BackgroundWorker is that the UI remains responsive because the UI thread is free while the work is done in the DoWork event handler. If the UI thread is waiting for the background work to finish then it's not free, so the UI doesn't remain responsive.
You can't have your cake and eat it too. Either the UI thread is free or it's not. You can't make the UI thread wait but still have it free. The BackgroundWorker has been made to work in a paraticular way. That's how it works and that's how you use it. Anything that you want to do specifically when the BackgroundWorker finishes you do in the RunWorkerCompleted event handler. That's what it's for and that's how you use it. It's proper programming. If you really feel that you need to do a hell of a lot more programming then you're not doing it right.
-
Mar 20th, 2011, 09:14 AM
#3
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
Well thank you for taking time to answer, great post.
-
Mar 21st, 2011, 03:38 PM
#4
Re: Wait for Backgroundworker to finish
I think the point was to show a progress bar.
I'm doing something similar for a project I'm tinkering on and I'll paste some relevant bits. I don't use the background worker, I just use the regular threading.
Here's how it does - I choose a file (I'm reading LWO files) and then this whole process starts. It not only updates a progress bar, but it also displays status messages. Code for this functionality:
In the FORM code, I call the following functions in my custom class:
Code:
System.Threading.Thread WorkMule = null;
public void SetWorkingFile(string File)
{
FileName = File;
Reader = new LwoFormatReader();
Reader.FileName = FileName;
WorkMule = new System.Threading.Thread(new System.Threading.ThreadStart(Reader.DoWork));
}
public void BeginWork()
{
pbLoad.Value = 100;
if(WorkMule != null)
{
WorkMule.Start();
}
}
That's what starts the processing. Here's some of what the LwoFormatReader looks like:
Code:
protected internal string FileName { get; set; }
private object ProgressLock = new object();
private object MessageLock = new object();
private int _BytesRead = 0;
private int _FileSize = 0;
private List<string> _Messages = new List<string>();
//other stuff
protected internal string Messages
{
get
{
lock(MessageLock)
{
int Start = Math.Max(0, _Messages.Count - 20);
int End = _Messages.Count - Start;
return string.Join("\r\n", _Messages.GetRange(Start, End).ToArray());
}
}
set
{
lock(MessageLock)
{
//if(_Messages.Count > 80)
// _Messages.RemoveAt(0);
_Messages.Add(value);
}
}
}
protected internal int Progress
{
get
{
lock(ProgressLock)
{
if(_FileSize == 0)
{
return 0;
}
return (int)(((double)BytesRead / (double)_FileSize) * 100);
}
}
}
protected internal int BytesRead
{
get
{
lock(ProgressLock)
{
return _BytesRead;
}
}
set
{
lock(ProgressLock)
{
_BytesRead = value;
}
}
}
protected internal int FileSize
{
get
{
lock(ProgressLock)
{
return _FileSize;
}
}
set
{
lock(ProgressLock)
{
_FileSize = value;
}
}
}
protected internal enum WorkStatus
{
NotStarted,
LoadingFile,
ReadingHeader,
ReadingChunk,
ReadingImages,
ReadingPoints,
ReadingPolys,
ReadingSurfaces,
ReadingTags,
ReadingUnknown,
ReadingVertices,
Loaded,
Error
}
private WorkStatus Status = WorkStatus.NotStarted;
private object StatusLock = new object();
protected internal WorkStatus GetStatus()
{
WorkStatus RetStatus = WorkStatus.NotStarted;
lock(StatusLock)
{
RetStatus = Status;
}
return RetStatus;
}
private void SetStatus(WorkStatus _Status)
{
lock(StatusLock)
{
Status = _Status;
}
}
protected internal string GetAllMessages()
{
return String.Join("\r\n", _Messages.ToArray());
}
protected internal string GetStringStatus()
{
switch(GetStatus())
{
case WorkStatus.Loaded:
return "Loaded";
case WorkStatus.LoadingFile:
return "Loading File";
case WorkStatus.NotStarted:
return "Waiting On Work";
case WorkStatus.ReadingChunk:
return "Reading Chunk Data";
case WorkStatus.ReadingHeader:
return "Reading Header";
case WorkStatus.ReadingImages:
return "Reading Image-based Data";
case WorkStatus.ReadingPoints:
return "Reading Point List";
case WorkStatus.ReadingPolys:
return "Reading Polygons";
case WorkStatus.ReadingSurfaces:
return "Reading Surfaces";
case WorkStatus.ReadingTags:
return "Reading Tags";
case WorkStatus.ReadingUnknown:
return "Reading Unknown Chunk";
case WorkStatus.ReadingVertices:
return "Reading Vertices";
case WorkStatus.Error:
return "An error has occurred";
default:
return "Status Error";
}
}
This lets me add messages by doing .Messages = "something" and they're appended. But it also lets me read the messages. The key here are the lock objects - they ensure that even though I'm about to access these on different threads (one for UI and one for processing) I don't run in to a thread unsafe operation.
As work is done in the reader, it does the following: (this is just one example)
Code:
//Inside a switch where I'm checking for different file sections I have:
case "tags":
SetStatus(WorkStatus.ReadingTags);
int TagsKnown = Tags.Count;
GetTags(ChunkBytes, Chunk.Size);
int TagsNow = Tags.Count;
BytesRead += Chunk.Size;
for(int i = TagsKnown ; i < TagsNow ; i++)
{
Messages = string.Format("\t{0}\tTag Found: {1}", i.ToString(), Tags[i]);
}
break;
The FORM has a timer on it. Here's the "tick" code. (I set the interval to 100ms and it's already turned on)
Code:
private void tStatus_Tick(object sender, EventArgs e)
{
if(Reader != null && bRead == true)
{
lblInfo.Text = Reader.GetStringStatus();
txtMessages.Text = Reader.Messages;
pbLoad.Value = Math.Min(Reader.Progress, 100); //Progress Bar
if(Reader.GetStatus() == LwoFormatReader.WorkStatus.Error ||
Reader.GetStatus() == LwoFormatReader.WorkStatus.Loaded)
{
txtMessages.Text = Reader.GetAllMessages();
txtMessages.ScrollBars = ScrollBars.Vertical;
txtMessages.SelectionStart = txtMessages.Text.Length - 1;
txtMessages.ScrollToCaret();
bRead = false;
//Other work
tStatus.Enabled = false;
}
}
So there's an example from real-world usage.
Need to re-register ASP.NET?
C:\WINNT\Microsoft.NET\Framework\v#VERSIONNUMBER#\aspnet_regiis -i
(Edit #VERSIONNUMBER# as needed - do a DIR if you don't know)
-
Mar 21st, 2011, 05:25 PM
#5
Re: Wait for Backgroundworker to finish
If the issue is indeed displaying progress then any reading about the BackgroundWorker will reveal that it has several members related to just that: the WorkerReportsProgress property, the ReportProgress method and the ProgressChanged event. There are many examples around of their use, including one that I posted on this site in the VB.NET CodeBank forum.
-
Mar 21st, 2011, 06:46 PM
#6
Re: Wait for Backgroundworker to finish
I think you've both missed the actual question being asked
 Originally Posted by Cyb3rH4Xter
I send a list with files to process to a void, DoThem(list).
Then in that void, if the file is a txt, send it to backgroundworker1. If the file is a jpg send it to backgroundworker2.
But I only want one backgroundworker to run at the same time (reporting progress to the same progressbar).
There are two background workers, but only one should be processing at any one time.
The answer, of course, is to have just one background worker, that processes both sorts of files.
I'm not sure what you mean by "sending" the files to the background worker. I would simply have the backgroundworker process the list. It sounds like you may be doing something a little strange, so if it isn't clear how to use a single backgroundworker, you may want to post your code so we can see if you're using it correctly.
-
Mar 21st, 2011, 08:38 PM
#7
Re: Wait for Backgroundworker to finish
 Originally Posted by Evil_Giraffe
I think you've both missed the actual question being asked
I think you may be right. In that case, the OP has things the wrong way around. Rather than one method to process the list and then two BackgroundWorkers to process individual files, it should be one BackgroundWorker to process the list and then two methods to process individual files. The DoWork event handler contains a For Each loop to process the list and an If or Select Case statement to decide which file-processing method to call.
-
Mar 22nd, 2011, 09:47 AM
#8
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
Evil Giraffe is right. And the answer by both of you are exactly what I was looking for and considered as the best alternative this morning. By sending I meant like set it as the argument and start bw1 and so on.
But before I start I then have one question: if I call a method in a bw it will be executed in the bw, right?
Then I will just need to do something like this:
Code:
bw_DoWork(...)
If File is jpg then
RunJPG(file)
Else If file is txt then
RunTXT(file)
End If
Oops, vb code, but hey, I used it as a "language", not "programming language" at the moment
-
Mar 22nd, 2011, 11:45 AM
#9
Re: Wait for Backgroundworker to finish
 Originally Posted by Cyb3rH4Xter
Evil Giraffe is right. And the answer by both of you are exactly what I was looking for and considered as the best alternative this morning. By sending I meant like set it as the argument and start bw1 and so on.
But before I start I then have one question: if I call a method in a bw it will be executed in the bw, right?
Then I will just need to do something like this:
Code:
bw_DoWork(...)
If File is jpg then
RunJPG(file)
Else If file is txt then
RunTXT(file)
End If
Oops, vb code, but hey, I used it as a "language", not "programming language" at the moment 
It'll be executed on the same thread that called it.
Set up your code like this:
Code:
MyWorkerClass ObjectName = new MyWorkerClass();
ObjectName.Data = Data; //IE Send it everything it needs in order to work
ObjectName.WorkType = MyWorkerClass.WorkTypes.Jpeg; //Or .Text - see below
WorkMule = new System.Threading.Thread(ObjectName.DoWork);
//Futher down, in the MyWorkerClass class
public enum WorkTypes{
Jpeg,
Text
}
public WorkTypes WorkType { get; set; }
public void DoWork(){
switch(WorkType){
case WorkTypes.Jpeg:
FunctionToProcessJpeg();
break;
case WorkTypes.Text:
FunctionToProcessText();
break;
}
}
This is all written on the fly - if there's an error I'm sure you'll be able to fix it right up with the help of the compiler, but this should give you the right idea of how to go about this.
Need to re-register ASP.NET?
C:\WINNT\Microsoft.NET\Framework\v#VERSIONNUMBER#\aspnet_regiis -i
(Edit #VERSIONNUMBER# as needed - do a DIR if you don't know)
-
Mar 22nd, 2011, 11:51 AM
#10
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
I see thank you for the code. Though there is one problem, how do I report the progress from those Functions?
For example in the function FunctionToProcessText I want it to report progress as it goes through the text, but how is that possible?
This is just an example as you know, in my code I am processing videofiles.
-
Mar 22nd, 2011, 01:10 PM
#11
Re: Wait for Backgroundworker to finish
My answer would be to review the first set of code that I pasted above.
That said, jmc mentioned that there's an intrinsic property to the background worker - I'm sure if you googled that, you'd find it lickety split.
Need to re-register ASP.NET?
C:\WINNT\Microsoft.NET\Framework\v#VERSIONNUMBER#\aspnet_regiis -i
(Edit #VERSIONNUMBER# as needed - do a DIR if you don't know)
-
Mar 22nd, 2011, 03:21 PM
#12
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
I took a look again at your code, figured that out with the timer before I wrote, but just wanted to know if there were a better method.
But I don't understand what you meant with the second line, my English is good but not the best 
I understand that it is about a property that jmc mentioned, but I couldn't find that and don't really know what to google.
But yeah basically I know what to do, so thank you for your help, now I can continue my work.
-
Mar 22nd, 2011, 10:42 PM
#13
Re: Wait for Backgroundworker to finish
 Originally Posted by Cyb3rH4Xter
I understand that it is about a property that jmc mentioned, but I couldn't find that and don't really know what to google.
Don't Google. Read the documentation.
-
Mar 23rd, 2011, 11:10 AM
#14
Re: Wait for Backgroundworker to finish
Google usually leads to not only the documentation, but additional sites with examples. =)
Regardless, I think he's on his way. Woot for that.
Need to re-register ASP.NET?
C:\WINNT\Microsoft.NET\Framework\v#VERSIONNUMBER#\aspnet_regiis -i
(Edit #VERSIONNUMBER# as needed - do a DIR if you don't know)
-
Mar 23rd, 2011, 11:17 AM
#15
Re: Wait for Backgroundworker to finish
 Originally Posted by Lord_Rat
Google usually leads to not only the documentation, but additional sites with examples. =)
Regardless, I think he's on his way. Woot for that.
The documentation always leads to the documentation. You can then search elsewhere for additional examples if required. I'm not suggesting that sources other than the documentation should be used. I'm stating that the documentation should always be the first source used, assuming that you know what type and/or member you need to read the documentation for. In this case, that type is the BackgroundWorker. How to report progress would have been obvious in that case. Other sources may well then not have been needed at all. I speak from my own experience, so I know that it's so.
-
Mar 23rd, 2011, 02:48 PM
#16
Re: Wait for Backgroundworker to finish
 Originally Posted by jmcilhinney
I speak from my own experience, so I know that it's so.
Same. =)
And I'm explaining my answer, not contradicting yours.
Need to re-register ASP.NET?
C:\WINNT\Microsoft.NET\Framework\v#VERSIONNUMBER#\aspnet_regiis -i
(Edit #VERSIONNUMBER# as needed - do a DIR if you don't know)
-
Mar 24th, 2011, 04:44 PM
#17
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
Thank you for both of your answers, will try to find what you mean.
EDIT:
Wow I feel quite dumb. Reporting the progress isn't hard, just calling bw.ReportProgress works from withing the function. But what I don't understand is how I am supposed to set the e.Result and the e.Cancel. Or have you already answered to that? :S
What I know you can't access those from anywhere.
Last edited by Cyb3rH4Xter; Mar 24th, 2011 at 05:25 PM.
-
Mar 24th, 2011, 06:17 PM
#18
Re: Wait for Backgroundworker to finish
Yes I have already answered that. I've pointed you to the CodeBank thread of mine dedicated to the BackgroundWorker and it has code examples that demonstrate both those properties.
-
Mar 25th, 2011, 05:26 PM
#19
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
Oh didn't see that point but checked you submission in the codebank but it didn't say anything about setting the Result and Cancel property in for example a function run from the backgroundworker?
One way I could make it is that I do the checking in the function and if the user cancels, I cancel and return like 0 back to the DoWork and then the DoWork sets the rest.
-
Mar 25th, 2011, 08:39 PM
#20
Re: Wait for Backgroundworker to finish
This situation is no different to many, many others that you've encountered before. The DoWork event handler is a method, just like any other method. In that method, you have an object and you want to set a property of that object based on what happens in another method. How would you usually do that? There are only two ways:
1. Pass the object to the other method and let it set the property.
2. Get a result from the other method and set the property based on that.
That is how programming works. It's irrelevant that you're using a BackgroundWorker and this is originating from the DoWork event handler. Methods are methods, objects are objects and properties are properties. Those would be your two choices in any method, even if there was no multi-threading at all.
-
Mar 26th, 2011, 02:41 AM
#21
Thread Starter
Hyperactive Member
Re: Wait for Backgroundworker to finish
Okay thank you. Problem Solved.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|