I am working on an application that searches the files in the directory provided using background worker... the problem is with the backgroundWorker1.RunWorkerAsync();
following is my code when i am trying to give multiple paths for searching the file i type in the textbox
private void toolStripTextBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == 13)
{
foreach (string s in listBox1.Items)
{
DirectoryInfo deer = new DirectoryInfo(s);
toolStripButton2.Visible = true;
//listView1.Items.Clear();
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync(deer);
}
else
MessageBox.Show("Can't run the worker twice!");
// backgroundWorker1.RunWorkerAsync(deer);
}
}
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
}
and i get the following error
This BackgroundWorker is currently busy and cannot run multiple tasks concurrently.
please help me out..
Not sure what you're trying to achieve here.
1) If you wish to run multiple tasks concurrently on different threads (i.e. to process each one of the items in the listBox1.Items), you will have to create separate threads or tasks to do so, and not use the same background worker.
2) If you simply wish to handle the overall processing of these items in the background without affecting (blocking) the UI you will need to use one background worker and pass it the entire collection.
In any case, the current code should not throw the error, unless you comment out the mbox and uncomment the other backgroundWorker1.RunWorkerAsync(deer);. If you do that, then you're basically trying to start the same thread before it finished it's previous work. If you don't do that, you're basically skipping items in the list from being processed until the thread becomes available again.
A general example of the 1st should look like this:
foreach (string s in listBox1.Items)
{
DirectoryInfo deer = new DirectoryInfo(s);
toolStripButton2.Visible = true;
Task.Run(() => TheDoWorkMethodYouUsed(deer);
}
A general example of the 2nd would be to modify your do work method to run over the entire collection, and passing that collection:
if (e.KeyValue == 13)
{
backgroundWorker1.RunWorkerAsync(listBox1.Items);
}
And in the DoWork method:
foreach (string s in passedList)
{
DirectoryInfo deer = new DirectoryInfo(s);
// continue with normal processing of the method
}
Use multiple Threads :
Create multiple threads and wait all of them to complete
Or
http://msdn.microsoft.com/en-us/library/ff649143.aspx
Related
This the picture of the application that I am trying to run:
when I try to click outside, move it, or minimize it, the window hangs:
my code:
public void Process()
{
// using (HalconDotNet.HWindowControl HWinCtrl = new HalconDotNet.HWindowControl())
// {
using (PitFinderEngine VisionEngine = new PitFinderEngine())
{
foreach (string jpegfile in JpegFiles)
{
try
{
string[] parts1 = jpegfile.Split('\\');
string[] parts2 = parts1[parts1.Length - 1].Split('.')[0].Split('_');
string row = parts2[parts2.Length - 2].Split('R')[1];
string col = parts2[parts2.Length - 1].Split('C')[1];
Results.Add(row + " " + col, VisionEngine.action(jpegfile, "Production"));
//FormControls.ProgressBar_DoStep();
}
catch (Exception e)
{
}
}
}
}
the "Process" is called in this manner:
public static Thread StartTheThread(string LN, string TN)
{
var t = new Thread(() => RealStart(LN, TN));
t.Start();
return t;
}
private static void RealStart(string ln, string tn) {
Lots[ln].Tiles[tn].Process();
}
public static void DoWork()
{
string[] Directories = Directory.GetDirectories(LotPictureFolder);
List<Thread> ThreadList = new List<Thread>();
foreach (string lot in Directories)
{
string[] parts = lot.Split('\\');
string LotName = parts[parts.Length - 1];
foreach (string tile in Lots[LotName].Tiles.Keys)
{
if (!Lots[LotName].Tiles[tile].VicFileFound)
{
ThreadList.Add(StartTheThread(LotName, tile));
}
}
}
bool AllDone = false;
while (!AllDone)
{
AllDone = true;
foreach (Thread th in ThreadList)
{
if (th.IsAlive)
{
AllDone = false;
}
}
}
}
it seems that
VisionEngine.action(jpegfile, "Production")
takes 10ms - 20ms to run and is responsible to hanging the window, if i were to move the window; meaning, that if i were to comment it off the problem will not be there, is it possible to isolate this code, I tried using threads, but the issue still persists, i cant use tasks as the platform is .Net3.5.
The problem is that when you run longer tasks for you application it blocks the UI until the order is done. That's because your task blocks the MainThread for this order, so the UI can't respond, since it's running in the MainThread as well. Because the UI does not respond to Windows it's telling you: Hey, watchout this window does not respond to any user actions currently.
Even though your application does a lot of stuff in the background (what you assigned your application to do), but this does not matter for the user and Windows. The problem is that once you click more on your application, the blocked UI, Windows will still notice that and suggest you to close the window, because it seems like the application is stuck.
Simply use Application.DoEvents() in your long running task. This behaves as the following:
Calling this method causes the current thread to be suspended while all waiting window messages are processed.
So it pauses your currently long running task, to process the Windows messages which came from e.g. the user input, so maximizing, moving, ... the window. After that it will continue working on your long running order.
Application.DoEvents();
This implies that if e.g. your method takes 10s to complete, calling Application.DoEvents() once makes your application process user actions only one time, what does not seem like a behaviour you want. So you have to call it multiple times. Note that this can make your running method significantly slower.
You don't seem to use a ThreadList at this point anymore. Your whole process method should start a new thread. Then make sure with events you modify the ProgressBar it's progress. Once all of that code runs on a seperate thread your UI shouldn't freeze because of that anymore.
I have function
void Search(string text) { ... }
Inside there are many SQLite queries like
List<Word> words = Database.connection.Table<Word>().Where(x => x.word == text).ToListAsync().Result;
And it's needed some time to complete this (about 3 sec).
At this moment interface is freezed.
It's not good. How to solve this problem and don't wait this function?
The bulk of your time is this bit of code
ToListAsync().Result
The LINQ statement itself does not do any work
xxx.Where(x => x.word == text)
until you request items from it. This can be either from a foreach statement, or a ToList statement. When you call ToListAsync you are requesting the work to be done asynchronously, which means that it will not tie up the UI thread. But then the .Result makes it synchronous. So, you are not taking advantage of the threading that is already provided. If you change the signature of the method and how you are getting the results, you'll be able to offload the work.
private async Task Search(string text)
{
// execute the LINQ query with the TPL
List<Word> words = await Database.connection.Table<Word>().Where(x => x.word == text).ToListAsync();
// we are back on the UI thread
foreach(Word word in words)
{
// do something
}
}
There is no need to create a BackgroundWorker or make your code more complex. If you are developing for Windows Phone 7, you'll want to add the Microsoft.Bcl.Async nuget package to your app.
A BackgroundWorker is a good class for a novice at using threads. It has a simple interface and can even provide feedback to feed a ProgressBar in the UI as the work progresses. You can find full details with examples in the How to use a background worker for Windows Phone page on MSDN. An example from the linked page:
private void bw_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);
}
}
}
This is the method that gets run on the background thread. You can see that you even have the possibility to cancel the long running process at any time. The ReportProgress method is used to pass back a value representing the amount of work done.
More newbie questions:
This code grabs a number of proxies from the list in the main window (I couldn't figure out how to make variables be available between different functions) and does a check on each one (simple httpwebrequest) and then adds them to a list called finishedProxies.
For some reason when I press the start button, the whole program hangs up. I was under the impression that Parallel creates separate threads for each action leaving the UI thread alone so that it's responsive?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
I've tried using the code that's commented out to make changes to the UI inside the Parallel.Foreach and it makes the program freeze after the start button is pressed. It's worked for me before but I used Thread class.
How can I update the UI from inside the Parallel.Foreach and how do I make Parallel.Foreach work so that it doesn't make the UI freeze up while it's working?
Here's the whole code.
You must not start the parallel processing in your UI thread. See the example under the "Avoid Executing Parallel Loops on the UI Thread" header in this page.
Update: Or, you can simply create a new thread manuall and start the processing inside that as I see you have done. There's nothing wrong with that too.
Also, as Jim Mischel points out, you are accessing the lists from multiple threads at the same time, so there are race conditions there. Either substitute ConcurrentBag for List, or wrap the lists inside a lock statement each time you access them.
A good way to circumvent the problems of not being able to write to the UI thread when using Parallel statements is to use the Task Factory and delegates, see the following code, I used this to iterate over a series of files in a directory, and process them in a Parallel.ForEach loop, after each file is processed the UI thread is signaled and updated:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
And the methods that do the actual UI changes:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Hope this helps!
If anyone's curious, I kinda figured it out but I'm not sure if that's good programming or any way to deal with the issue.
I created a new thread like so:
Thread t = new Thread(do_checks);
t.Start();
and put away all of the parallel stuff inside of do_checks().
Seems to be doing okay.
One problem with your code is that you're calling FinishedProxies.Add from multiple threads concurrently. That's going to cause a problem because List<T> isn't thread-safe. You'll need to protect it with a lock or some other synchronization primitive, or use a concurrent collection.
Whether that causes the UI lockup, I don't know. Without more information, it's hard to say. If the proxies list is very long and checkProxy doesn't take long to execute, then your tasks will all queue up behind that Invoke call. That's going to cause a whole bunch of pending UI updates. That will lock up the UI because the UI thread is busy servicing those queued requests.
This is what I think might be happening in your code-base.
Normal Scenario: You click on button. Do not use Parallel.Foreach loop. Use Dispatcher class and push the code to run on separate thread in background. Once the background thread is done processing, it will invoke the main UI thread for updating the UI. In this scenario, the background thread(invoked via Dispatcher) knows about the main UI thread, which it needs to callback. Or simply said the main UI thread has its own identity.
Using Parallel.Foreach loop: Once you invoke Paralle.Foreach loop, the framework uses the threadpool thread. ThreadPool threads are chosen randomly and the executing code should never make any assumption on the identity of the chosen thread. In the original code its very much possible that dispatcher thread invoked via Parallel.Foreach loop is not able to figure out the thread which it is associated with. When you use explicit thread, then it works fine because the explicit thread has its own identity which can be relied upon by the executing code.
Ideally if your main concern is all about keeping UI responsive, then you should first use the Dispatcher class to push the code in background thread and then in there use what ever logic you want to speedup the overall execution.
if you want to use parallel foreach in GUI control like button click etc
then put parallel foreach in Task.Factory.StartNew
like
private void start_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(() =>
Parallel.ForEach(YourArrayList, (ArraySingleValue) =>
{
Console.WriteLine("your background process code goes here for:"+ArraySingleValue);
})
);
}//func end
it will resolve freeze/stuck or hang issue
In my application, there is a list of images through which the user can step. Image loading is slow, so to improve user experience I would like to preload some images in the background (e.g. those images in the list succeeding the currently selected one).
I've never really used threads in C#, so I am looking for some kind of "best practice" advice how to implement the following behaviour:
public Image LoadCachedImage(string path)
{
// check if the cache (being operated in the background)
// has preloaded the image
Image result = TryGetFromCache(path);
if (result == null) { result = LoadSynchronously(path); }
// somehow get a list of images that should be preloaded,
// e.g. the successors in the list
string[] candidates = GetCandidates(path);
// trigger loading of "candidates" in the background, so they will
// be in the cache when queried later
EnqueueForPreloading(candidates);
return result;
}
I believe, a background thread should be monitoring the queue, and consecutively process the elements that are posted through EnqueueForPreloading(). I would like to know how to implement this "main loop" of the background worker thread (or maybe there is a better way to do this?)
If you really need sequential processing of the candidates, you can do one of the following:
Create a message queue data structure that has a AutoResetEvent. The class should spawn a thread that waits on the event and then processes everything in the queue. The class's Add or Enqueue should add it to the queue and then set the event. This would release the thread, which processes the items in the queue.
Create a class that starts an STA thread, creates a System.Windows.Forms.Control, and then enters Application.Run(). Every time you want to process an image asynchronously, call Control.BeginInvoke(...) and the STA thread will pick it up in its message queue.
There are probably other alternatives, but these two would be what I would try.
If you don't actually need sequential processing, consider using ThreadPool.QueueUserWorkItem(...). If there are free pool threads, it will use them, otherwise it will queue up the items. But you won't be guaranteed order of processing, and several may/will get processed concurrently.
Here's a (flawed) example of a message queue:
class MyBackgroundQueue<T>
{
private Queue<T> _queue = new Queue<T>();
private System.Threading.AutoResetEvent _event = new System.Threading.AutoResetEvent(false);
private System.Threading.Thread _thread;
public void Start()
{
_thread = new System.Threading.Thread(new System.Threading.ThreadStart(ProcessQueueWorker));
_thread.Start();
}
public class ItemEventArgs : EventArgs
{ public T Item { get; set; } }
public event EventHandler<ItemEventArgs> ProcessItem;
private void ProcessQueueWorker()
{
while (true)
{
_event.WaitOne();
while (_queue.Count > 0)
ProcessItem(this, new ItemEventArgs { Item = _queue.Dequeue() });
}
}
public void Enqueue(T item)
{
_queue.Enqueue(item);
_event.Set();
}
}
One flaw here, of course, are that _queue is not locked so you'll run into race conditions. But I'll leave it to you to fix that (e.g. use the 2 queue swap method). Also, the while(true) never breaks, but I hope the sample serves your purpose.
This is what I call cheat caching. The operating system already caches files for you, but you have to access them first. So what you can do is just load the files but don't save a reference to them.
You can do this without multi-threading per-se, and without holding the images in a list. Just create a method delegate and invoke for each file you want to load in the background.
For example, pre-loading all the jpeg images in a directory.
Action<string> d = (string file) => { System.Drawing.Image.FromFile(file); };
foreach(string file in dir.GetFiles("*.jpg"))
d.BeginInvoke(file);
BeginInvoke() is a multi-threaded approach to this, that loop will go very fast, but each file will be loaded on a different thread. Or you could change that up a little to put the loop inside the delegate, aka.
public void PreCache(List<string> files)
{
foreach(string file in files)
System.Drawing.Image.FromFile(file);
}
Then in your code
Action<List<string>> d = PreCache;
d.BeginInvoke(theList);
Then all the loading is done on just one worker thread.
I am trying to populate a text box with some data, namely the names of several instruments a line at a time.
I have a class that will generate and return a list of instruments, I then iterate through the list and append a new line to the text box after each iteration.
Starting the Thread:
private void buttonListInstruments_Click(object sender, EventArgs e)
{
if (ins == null)
{
ins = new Thread(GetListOfInstruments);
ins.Start();
}
else if (ins != null)
{
textBoxLog.AppendText("Instruments still updating..");
}
}
Delegate to update textbox:
public delegate void UpdateLogWithInstrumentsCallback(List<Instrument> instruments);
private void UpdateInstruments(List<Instrument> instruments)
{
textBoxLog.AppendText("Listing available Instruments...\n");
foreach (var value in instruments)
{
textBoxLog.AppendText(value.ToString() + "\n");
}
textBoxLog.AppendText("End of list. \n");
ins = null;
}
Invoking the control:
private void GetListOfInstruments()
{
textBoxLog.Invoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
}
Note: GetInstruments() returns a List of type Instrument.
I am implementing therads to try to keep the GUI functional whilst the text box updates.
For some reason the other UI controls on the WinForm such as a seperate combo box remain inactive when pressed until the text box has finished updating.
Am I using threads correctly?
Thanks.
You haven't accomplished anything, the UpdateInstruments() method still runs on the UI thread, just like it did before. Not so sure why you see such a long delay, that must be a large number of instruments. You can possibly make it is less slow by first appending all of them into a StringBuilder, then append its ToString() value to the TextBox. That cuts out the fairly expensive Windows call.
I would recommend using a SynchronizationContext in general:
From the UI thread, e.g. initialization:
// make sure a SC is created automatically
Forms.WindowsFormsSynchronizationContext.AutoInstall = true;
// a control needs to exist prior to getting the SC for WinForms
// (any control will do)
var syncControl = new Forms.Control();
syncControl.CreateControl();
SyncrhonizationContext winformsContext = System.Threading.SynchronizationContext.Current;
Later on, from any thread wishing to post to the above SC:
// later on -- no need to worry about Invoke/BeginInvoke! Whoo!
// Post will run async and will guarantee a post to the UI message queue
// that is, this returns immediately
// it is OKAY to call this from the UI thread or a non-UI thread
winformsContext.Post(((state) => ..., someState);
As others have pointed out, either make the UI update action quicker (this is the better method!!!) or separate it into multiple actions posted to the UI queue (if you post into the queue then other message in the queue won't be blocked). Here is an example of "chunking" the operations into little bit of time until it's all done -- it assumes UpdateStuff is called after the data is collected and not necessarily suitable when the collection itself takes noticeable time. This doesn't take "stopping" into account and is sort of messy as it uses a closure instead of passing the state. Anyway, enjoy.
void UpdateStuff (List<string> _stuff) {
var stuff = new Queue<string>(_stuff); // make copy
SendOrPostCallback fn = null; // silly so we can access in closure
fn = (_state) => {
// this is in UI thread
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < 20 && stuff.Count > 0) {
var item = stuff.Dequeue();
// do stuff with item
}
if (stuff.Count > 0) {
// have more stuff. we may have run out of our "time-slice"
winformsContext.Post(fn, null);
}
};
winformsContext.Post(fn, null);
}
Happy coding.
Change this line:
textBoxLog.Invoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
with this:
textBoxLog.BeginInvoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
You are feeding all instruments into the textbox at once rather then one-by-one in terms of threading. The call to Invoke shall be placed in the for-loop and not to surround it.
nope, you start a thread, and then use invoke, which basically means you are going back to the UI thread to do the work... so your thread does nothing!
You might find that it's more efficient to build a string first and append to the textbox in one chunk, instead of line-by-line. The string concatenation operation could then be done on the helper thread as well.