M
M
monastrel2014-03-15 00:08:52
Message Queues
monastrel, 2014-03-15 00:08:52

How to transfer code execution from Queue and yield to a thread (Thread/Task/etc) so as not to freeze the form?

Good afternoon.
There is a C# WinForms .NET 4 - 4.5 application. There is the following code:

public class SuperClass: ClassName
{}

public abstract class ClassName
{
      public static IEnumerable<ClassName> GetAll(string param)
      {
           var queue = new Queue<string>();
           var cacheableData = new HashSet<string>();
           queue.Enqueue(param);

           while (queue.Count > 0)
           {
               HttpWebRequest request = new HttpWebRequest.Create(param);
               // ... логика обработки http запроса
               yield return new SubClass {}

               // ... еще логика разная
               // paramNext = ...
               cacheableData.Add(paramNext);
               queue.Enqueue(paramNext);
           }
      }

      public class SubClass : ClassName
      { }
}

// .. выполнение кода на форме

var classResult = ClassName.GetAll("xxx");

foreach (ClassName result in classResult )
{
   /// что-то делаю с result  , заполняю инфу в ListBox
}

Its essence is to get some value, process it, add new parameters to the queue, and so on until I get all the data (let it be some kind of web spider thread that parses links on the page and adds them to the queue, or some kind of email- s).
When such code is executed, the application, of course, hangs (freezes). Doesn't even help: I
Application.DoEvents();
​​thought about moving code execution to a thread (Thread, Task, maybe something else, I'm still not very good at this topic). But I don’t know how to do this (and is it possible with yield, or will it be necessary to write some events, delegates, maybe something else). Help me figure this out, please.
Thank you!

Answer the question

In order to leave comments, you need to log in

3 answer(s)
K
Kerman, 2014-03-15
@Kerman

It's better to use something like BackgroundWorker. It has a ProgressChanged event through which you can return a ClassName to the main thread.

M
monastrel, 2014-03-15
@monastrel

2 Kerman
I tried to do like this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            foreach (ClassName result in SuperClass.GetAll("xxx"))
            {
                worker.ReportProgress(0, result );
            }
        }

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ClassName result = (ClassName )e.UserState;

            listBox1.Items.Add(result.Param);
        }

But the code stopped working (the class code didn't change at all). More precisely, information began to appear that was not without BackgroundWorker O_o Maybe asynchrony is to blame? Or I don't know what

G
gleb_kudr, 2014-03-15
@gleb_kudr

Two options.
1. Background Worker. This is a separate thread, it does work (the work method) in a background thread, control is returned to the parent thread either after a change in progress or at the end of the work. There are examples on msdn . Just remember about thread safety - do not change the collection from another thread in the process.
2. Async/await pattern from .net 4.5 This design does not create separate threads and allows everything to be done in the main thread, so it is inherently thread-safe. There are also a bunch of examples on msdn .
Personally, I recommend just copy-pasting the examples from msdn and then gradually changing them to your own code in order to understand what the essence of the methods is and what problems can arise. BackgroundWorker is a rather complex pattern, it is better to understand it first with an elementary example.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question