Мне нужна помощь с использованием потоков в C #

2

Я разрабатываю программное обеспечение на С#, которое использует статические функции из файла С++.dll через Wrapper.

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

Есть ли способ исправить это?

Спасибо заранее.

PS: Вот код из моей программы:

public partial class MainForm : Form, IMultiLanguage
{
      //...

      //This method is subscribed to the event of pressing the 'Abort' button
      private void StopCurrentAnalisis()
      {
            try
            {
                this.analisisManagerController.AnalisisThread.Abort();
            }
            catch (Exception e){  }
            finally
            {
                MessageBox.Show("Analisis has been cancelled by user", "Analisis Interrupted", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                CerrarNowLoadingForm();
            }
      }

      //..
}

public class AnalisisManager: IAnalisisManagerController
{
    //..
    private Thread analisisThread;
    public Thread AnalisisThread{get{return this.analisisThread;}}


    public void MakePadrobAnalisis(TipoAnalisis tipoAnalisis,
        Dictionary<string, Dictionary<int, double>> parametros)
    {
        object[] arregloParams = new object[]{tipoAnalisis,parametros};
        analisisThread = new Thread(new ParameterizedThreadStart(MakeAnalisisInOtherThread));
        analisisThread.Start(arregloParams);
    }

 private void MakeAnalisisInOtherThread(object o)
    {
        object[] arregloParams = o as object[];
        TipoAnalisis tipoAnalisis = (TipoAnalisis) arregloParams[0];
        Dictionary<string, Dictionary<int, double>> parametros = arregloParams[1] as Dictionary<string, Dictionary<int, double>>;

        //This launches an event telling the GUI the unstable analisis has started.
        //The method that makes the 'Abort' button to appear on the GUI is subscribed to this event
        StartAnalisis();

       //The Thread executes DLL functions according to tipoAnalisis, for example:
       case InvKinematicsMinTorque:
       {
           WrapperPadirob.InverseKinematicsMinTorqueConfigAnalisis();
           break;
       }
       //..
   }
}
  • 0
    Можете ли вы опубликовать часть своего кода?
  • 0
    Действительно зависит от библиотеки ...
Теги:
multithreading
process

5 ответов

5
Лучший ответ

Однако, когда я прерываю этот поток из основного потока

Это ваша проблема. Вы не должны использовать Thread.Abort. Ознакомьтесь с "Отказ от зла" в в этой статье для лучшего подхода. Оттуда...

Подход, который я всегда рекомендую, мертвый просто. Имейте volatile bool поле, которое отображается как на вашем рабочий поток и поток пользовательского интерфейса. Если пользователь нажимает кнопку "Отменить", установите этот флаг. Между тем, на вашей рабочей нити, проверьте флаг время от времени. Если ты видишь он будет установлен, прекратите то, что вы делаете.

Кроме того, очень хорошее обсуждение этого в потоке SO.

За комментарий:

У вас есть эта тема...

Thread AnalisisThread{get{return this.analisisThread;}}

... он выполняет делегат, указывающий на...

private void MakeAnalisisInOtherThread(object o)

... у вас также есть этот метод. Если интерфейс С++ не имеет разумного метода .StopAnalysis(или чего-то подобного), вы должны подождать, пока анализ не будет выполнен, а затем опросить основной поток, как описано в статьях. Взорвать поток, чтобы остановить анализ, - это не то, что нужно делать.

  • 0
    Я с нетерпением жду принятия такого решения, но как я могу заставить поток читать значение bool, если он выполняет библиотеку C ++, к которой у меня нет доступа ?. Спасибо
  • 0
    @JP, есть комментарии к моему ответу?
1

Напомним: у вас есть неуправляемый код это неустойчиво, что вам нужно из вашего приложения С# и ищет лучший способ потребления это.

Извините, что сказал, но ваш текущий дизайн испорчен, если вы прервите поток, пока он запускает какой-то произвольный неуправляемый код, вы рискуете повредить свое приложение. У меня могут быть утечки, может течь, вы можете вызвать всевозможные невероятно сложные отладки concurrency.

Чтобы решить эту проблему, я бы рекомендовал:

  • Лучшее решение: устранить неуправляемую dll.
  • Второе лучшее решение: запустите отдельный процесс, единственная ответственность которого заключается в том, чтобы взаимодействовать с DLL-проблемой, если что-то играет вверх, завершает процесс, а затем запускает его снова. Свяжите ваше основное приложение с этим процессом, используя удаленный доступ или WCF.
  • 0
    Сэм, я согласен. Дополнительного уровня косвенности может быть достаточно, чтобы процесс мог завершиться без необходимости взорвать его. Суть в том, что вы совершенно правы в том, что бесцеремонное разрывание нити является рецептом неуправляемой катастрофы. :) +1
1

Вместо того, чтобы создавать и убивать потоки все время, лучше создать один поток, который запускает такой код:

private void Worker()
{
    while (m_bRunning)
    {

         m_autoResetEvent.WaitOne();
         DoWork(); // eg. call all required functions, maybe by popping requests off a queue
    }
}

Затем вы можете Set событие auto- reset, которое пробудит поток от приостановки и будет обслуживать один запрос.

Это имеет дополнительное преимущество, что все вызовы будут выполняться в DLL из одного потока.

1

Кстати, ваша С++ dll написана для работы в нескольких потоках? Возможно, он использует методы, которые работают только при использовании только одного потока. Запустите его в нескольких потоках, и могут произойти очень неприятные вещи, например, разные пользователи, обращающиеся к данным других, или код, перезаписывающий кучу библиотеки времени выполнения C.

0

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

[DllImport ("mydll.dll")]
private extern void method_call ();

private void thing_1 ()
{
  dll_method_call failing_method;
  IAsycResult method_result;
  Int32 method_timeout;

  method_timeout = 15000;
  failing_method = method_call;
  method_result = failing_method.BeginInvoke (null, null);
  if (method_result.AsyncWaitHandle.WaitOne (method_timeout))
  {
    method_result.EndInvoke ();
    //Success
  }
  else
  {
    //Failure
  }
}

private delegate void dll_method_call ();

Ещё вопросы

Сообщество Overcoder
Наверх
Меню