Многопоточность внутри потоков и циклов ожидания WinForms и C # - PullRequest
0 голосов
/ 24 ноября 2011

У меня проблемы с этим кодом.Я использую .Net (C #) с приложением Winform.

Мне нужно запустить метод RunProgram, который имеет цикл, который делает вызов метода с именем ListLoop.В этой функции есть задание, которое создает 1 поток для каждого элемента списка.

(Пожалуйста, прочитайте код, прежде чем продолжить читать описание, чтобы вы могли понять, о чем я говорю)

Проблема в том, что если я не сделаю никакого контроля в "for" (Метод RunProgram) он запускает (конечно) 10 раз функцию ListLoop.Поэтому я бы добавил в это «For» код, который ожидает завершения всех потоков, поэтому я могу сделать что-то, а затем продолжить со следующим циклом.

Я попробовал thread.join (), но он заморозил мое приложение пользовательского интерфейса (это приложение, которое внутри имеет браузер WebControl).

Даже если я попробую поиграть с returnThred и с thread.isAlive, он все равно замораживает пользовательский интерфейс.

Если бы у меня не было многопоточности, я бы не остался здесь с этими проблемами, но это единственноея думаю, что это хорошее решение для моей программы.

Есть ли простое решение для моего кода?Обновление: Может быть, это не ясно, мой вопрос.

Я просто хочу запустить ListLoop X раз, но перед тем, как начать следующий, я хочу подождать, пока все потоки не будут работать (те, что были при первом вызове), так что я могу сделать некоторый контроль и продолжить циклвнутри RunProgram.

Update2 У меня есть это приложение пользовательского интерфейса, которое имеет элемент управления WebBrowser.У меня есть объект списка ссылок (каждый элемент этого класса имеет строку url и idHost = 1 2 3 4 ... 1 для google 2 для yahoo и т. Д.). Я хочу сделать цикл, в котором моя программа запускает newTab (сМетод AddTab (url)) для каждого элемента списка.Когда все ссылки открыты (и поэтому все потоки являются мертвыми и), мне нужно сделать что-то, что посчитает, сколько открытых страниц и кто был idHost, сохранит его и запустит еще один цикл со списком (этот список берет случайный элемент из большого списка)

Обновление 3 Я только что попробовал с BackGround Worker, но я не могу использовать его, потому что WebKit, который я использую, дает ошибку COM.Кое-что для задач.

Спасибо

private void RunProgram()
{
  List<Links> TheList = new List<Links>();
  //Do something to Populate the List
  List<System.Threading.Thread> returnThread = new List<.....>();
  for(int i=0; i<10; i++)
  {
    returnThread=ListLoop(TheList);
       //      ???????????
      //   When Loop Method has finished and all threads stopped
     //    Do something
    //     Continue for the next Loop
  }
}

private List<System.Threading.Thread> ListLoop(List<Links> list)
{
  List<System.Threading.Thread> threading = new List<System.Threading.Thread>();
  foreach (Links link in list)
  {
    Links tmp = new Links();
    tmp = link;

    var thread = new System.Threading.Thread(p =>
    {
      lock (l)
      {
        Action action = () =>
        {
          AddTab(tmp);
        };
        this.Invoke(action);

        if (tmp.idHost == 1) //if IDhost == Google wait 5sec
        {
          System.Threading.Thread.Sleep(5000);
        }
        else
        {
          System.Threading.Thread.Sleep(2000);
        }
      }
    });
    threading.Add(thread);
    thread.Start();
  }
  return threading;
}

Ответы [ 2 ]

0 голосов
/ 24 ноября 2011

Если RunProgram вызывается из вашего основного приложения, оно замораживает вашу основную форму, если оно спит или ожидает завершения потоков.Вам следует запустить метод RunProgram в его собственном потоке, чтобы он мог затем создать рабочие потоки, а затем вы можете дождаться завершения потоков в цикле for, прежде чем начинать новые.

Вы можете использовать AutoResetEvent для оповещения о завершении потоков, поэтому вы можете просто подождать AutoResetEvent, прежде чем продолжить цикл.Класс BackgroundWorker может также подойти для создания ваших потоков.

0 голосов
/ 24 ноября 2011

Я не уверен, правильно ли я понял ваш вопрос, но:

Вы работаете здесь асинхронно ... Вы не можете ждать в своем коде без остановки графического интерфейса.

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

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

ОБНОВЛЕНИЕ: Вот пример того, как блокирующая функция, которая не блокирует поток GUI:

using System.Windows.Forms;
using System.Threading;
using System;

namespace Threads
{
    public partial class Form1 : Form
    {
        public event EventHandler OnSomethingFinishes;


        public Form1()
        {
            InitializeComponent();

            OnSomethingFinishes += new EventHandler(Form1_OnSomethingFinishes);
        }

        void Form1_OnSomethingFinishes(object sender, EventArgs e)
        {
            this.Invoke(new EventHandler(Form1_OnSomethingFinishesSafe), sender, e);
        }

        void Form1_OnSomethingFinishesSafe(object sender, EventArgs e)
        {
            this.Text = "Done!";
        }

        private void BlockingFunction(object a_oParameter)
        {
            // Do something that blocks
            Thread.Sleep(2000);

            if (OnSomethingFinishes != null)
                OnSomethingFinishes(this, null);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread l_oThread = new Thread(BlockingFunction);
            l_oThread.Start();

            this.Text = "Please Wait...";
        }
    }
}

button1 запускает процесс.Обратите внимание, что вам нужно вызывать функцию после обработки события, чтобы переместить элемент управления в основной поток GUI

Надеюсь, это поможет

...