Прогресс потока к GUI - PullRequest
       15

Прогресс потока к GUI

0 голосов
/ 06 февраля 2009

Я реализовал многопоточность в своем приложении для очистки веб-сайтов. После того, как все сайты удалены, я хочу обработать их.

форма создает queueworker (который создает 2 рабочих и обрабатывает задачи). После того, как все задачи выполнены, я хочу обработать их обратно в форму. В этот момент я получил это с

public void WaitForCompletion()
    {
        // Enqueue one null task per worker to make each exit.
        StopWorkers();

        //wait for the workers to finish
        foreach (Thread worker in workers)
        {
            worker.Join();
        }
    }

После того, как задание выполнено, я запускаю (из очереди):

public event EventHandler<ProgressEvent> UrlScanned;   

if (UrlScanned != null)
{ 
         UrlScanned(this, new ProgressEvent(task.Name, 1));
}

И поймать это событие с:

urlscanner.UrlScanned += new EventHandler<ProgressEvent>(UrlScanningProgress);     

private void UrlScanningProgress(object sender, ProgressEvent args)
{
   if (pbarurlScan.InvokeRequired)
   {
       //don't use invoke when Thread.Join() is used! Deadlock
       Invoke(new MethodInvoker(delegate() { UrlScanningProgress(sender, args); 
       //BeginInvoke(new MethodInvoker(delegate() { UrlScanningProgress(sender, args)};
   }
   else
   {
                pbarurlScan.Value++;
   }
}

Проблема в том, что форма-поток блокируется, и при вызове Invoke все приложение теперь находится в тупиковой ситуации.

Как я могу дать обновление формы, не имея тупиков, и получить немедленное обновление (begininvoke происходит, если рабочие потоки завершены)

Ответы [ 2 ]

2 голосов
/ 06 февраля 2009

Почему вы делаете Join? Я бы поднял обратный вызов в конце каждого потока - возможно, уменьшив счетчик. Когда счетчик достигает 0, , затем перезванивают в поток пользовательского интерфейса и выполняют код "все готово"; что-то вроде:

using System.Windows.Forms;
using System.Threading;
using System;
class MyForm : Form
{

    public MyForm()
    {
        Button btn = new Button();
        Controls.Add(btn);
        btn.Text = "Go";
        btn.Click += btn_Click;
    }
    int counter;
    void btn_Click(object sender, System.EventArgs e)
    {
        for (int i = 0; i < 5; i++)
        {
            Interlocked.Increment(ref counter);
            ThreadPool.QueueUserWorkItem(DoWork, i);
        }
    }
    void DoWork(object state)
    {
        for (int i = 0; i < 10; i++)
        { // send progress
            BeginInvoke((Action)delegate { Text += state.ToString(); });
            Thread.Sleep(500);
        }
        EndThread(); // this thread done
    }
    void EndThread()
    {
        if (Interlocked.Decrement(ref counter) == 0)
        {
            AllDone();
        }
    }
    void AllDone()
    {
        Invoke((Action)delegate { this.Text += " all done!"; });
    }
    [STAThread]
    static void Main()
    {
        Application.Run(new MyForm());
    }
}
0 голосов
/ 06 февраля 2009

Теперь я запускаю отдельное событие, когда все задачи выполнены. Я переместил логику для обработки задач в отдельную функцию, которая будет вызываться при получении события AllUrlsScanned.

...