Подтвердить что ты не робот

Запуск нескольких потоков и отслеживание их из моего приложения .NET

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

Пример == > Запустите Thread Alpha, запустите Thread Beta.. тогда в любой момент моего приложения я должен был бы сказать Terminate Thread Beta..

Каков наилучший способ отслеживания открытых потоков в .NET и что мне нужно знать (id?) о потоке, чтобы его прервать? Пример кода, учебник будет полезен.

4b9b3361

Ответ 1

Вы можете сэкономить на работе осла и использовать этот Smart Thread Pool. Он предоставляет единицу рабочей системы, которая позволяет вам запрашивать каждый статус потока в любой точке и завершать их.

Если это слишком беспокоит, то, как упоминалось, IDictionary<string,Thread>, вероятно, является самым простым решением. Или даже проще дать каждому из ваших потоков имя и использовать IList<Thread>:

public class MyThreadPool
{
    private IList<Thread> _threads;
    private readonly int MAX_THREADS = 25;

    public MyThreadPool()
    {
        _threads = new List<Thread>();
    }

    public void LaunchThreads()
    {
        for (int i = 0; i < MAX_THREADS;i++)
        {
            Thread thread = new Thread(ThreadEntry);
            thread.IsBackground = true;
            thread.Name = string.Format("MyThread{0}",i);

            _threads.Add(thread);
            thread.Start();
        }
    }

    public void KillThread(int index)
    {
        string id = string.Format("MyThread{0}",index);
        foreach (Thread thread in _threads)
        {
            if (thread.Name == id)
                thread.Abort();
        }
    }

    void ThreadEntry()
    {

    }
}

Вы можете, конечно, намного больше заниматься и усложнять его. Если убить ваши потоки не чувствительно к времени (например, если вам не нужно убивать поток через 3 секунды в пользовательском интерфейсе), то Thread.Join() - лучшая практика.

И если вы еще этого не читали, то у Jon Skeet это хорошее обсуждение и решение для "не использовать прерывание" советы, общие для SO.

Ответ 2

Вы можете создать словарь потоков и присвоить им идентификаторы, например:

Dictionary<string, Thread> threads = new Dictionary<string, Thread>();
for(int i = 0 ;i < numOfThreads;i++)
{
    Thread thread = new Thread(new ThreadStart(MethodToExe));
    thread.Name = threadName; //Any name you want to assign
    thread.Start(); //If you wish to start them straight away and call MethodToExe
    threads.Add(id, thread);
}

Если вы не хотите сохранять потоки против Id, вы можете использовать список, а позже просто перечислите его, чтобы убить потоки.

И когда вы хотите их прекратить, вы можете прервать их. Лучше иметь какое-то условие в вашем MethodToExe, которое позволяет оставить этот метод, позволяя потоку прекратить изящество. Что-то вроде:

void MethodToExe()
{
   while(_isRunning)
   {
      //you code here//
      if(!_isRunning)
      {
          break;
      }
      //you code here//
   }
}

Чтобы прервать, вы можете перечислить словарь и вызвать Thread.Abort(). Будьте готовы поймать ThreadAbortException

Ответ 3

Я задал аналогичные вопросы и получил кучу хороших ответов: Выключение многопоточного приложения

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

Главное помнить, что если вы хотите, чтобы ваши потоки не прерывали процесс, вы должны установить все свои потоки в фоновом режиме:

Thread thread = new Thread(new ThreadStart(testObject.RunLoop));
thread.IsBackground = true;
thread.start();

Предпочтительный способ запуска и управления потоками - это ThreadPool, но практически любой контейнер может использоваться для хранения ссылок на ваши потоки. В ваших потоках всегда должен быть флаг, который сообщает им о завершении, и они должны постоянно проверять его.

Кроме того, для лучшего управления вы можете снабжать свои потоки CountdownLatch: всякий раз, когда поток выходит из цикла, он будет сигнализировать о CountdownLatch. Ваш основной поток вызовет метод CountdownLatch.Wait(), и он будет блокироваться до тех пор, пока все потоки не будут сигнализированы... это позволяет правильно очистить и гарантирует, что все ваши потоки будут отключены, прежде чем вы начнете очистку.

public class CountdownLatch
{
    private int m_remain;
    private EventWaitHandle m_event;

    public CountdownLatch(int count)
    {
        Reset(count);
    }

    public void Reset(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}

Также стоит упомянуть, что метод Thread.Abort() выполняет некоторые странные вещи:

Когда поток вызывает Abort сам по себе, эффект подобен бросанию исключение; исключение ThreadAbortException происходит немедленно, и результат предсказуемы. Однако, если один поток вызывает прерывание в другом потоке, прерывание прерывает любой код Бег. Существует также вероятность того, что статический конструктор может быть прерван. В редких случаях это может экземпляры этого класса из созданный в этом домене приложения. В версии .NET Framework версии 1.0 и 1.1, есть вероятность, что поток может прервать, когда блок finally и в этом случае, наконец, блок прерван.

Поток, который вызывает Abort, может блокировать, если поток, который прерывается в защищенном регионе код, такой как блок catch, наконец блок или ограниченное выполнение область. Если поток, вызывающий Abort удерживает блокировку, что прерванная нить требуется, может возникнуть взаимоблокировка.

Ответ 4

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

var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault();
if(myThread != null)
    myThread.Abort();

Ответ 5

Зависит от того, насколько сложной она вам нужна. Вы можете реализовать собственный тип ThreadPool с помощью вспомогательных методов и т.д. Однако я считаю, что это просто, просто поддерживая список/массив и добавляя/удаляя потоки в/из коллекции соответственно.

Вы также можете использовать коллекцию Dictionary и использовать свой собственный тип конкретного ключа для извлечения их, т.е. гидов/строк.

Ответ 6

Ничего себе, есть так много ответов.

  • Вы можете просто использовать массив для хранения потоков, это будет работать, только если доступ к массиву будет секвенциальным, но если у вас будет другой поток, обращающийся к этому массиву, вам нужно будет синхронизировать доступ
  • Вы можете использовать пул потоков, но пул потоков очень ограничен и может содержать только фиксированное количество потоков.
  • Как уже упоминалось выше, вы можете создать свой собственный пул потоков, который в .NET v4 становится намного проще с введением безопасных коллекций.
  • вы можете управлять ими, удерживая список объектов mutex, которые будут определять, когда эти потоки будут завершены, потоки будут запрашивать мьютекс каждый раз, когда они будут выполняться, прежде чем делать что-либо еще, и если его набор завершает работу, вы можете управлять mutex из любого места, а так как мьютекс - по защитой от нитей, он довольно прост.

Я могу думать о еще 10 способах, но они, похоже, работают. сообщите мне, если они не соответствуют вашим потребностям.

Ответ 7

Когда вы начинаете каждый поток, поместите его ManagedThreadId в словарь как ключ и экземпляр потока как значение. Используйте обратный вызов из каждого потока, чтобы вернуть его ManagedThreadId, который вы можете использовать для удаления потока из Словаря, когда он завершается. Вы также можете использовать словарь для прерывания потоков, если это необходимо. Создайте потоки фоновых потоков, чтобы они прекратились, если ваше приложение неожиданно завершилось.

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