Задача запущена из Threading.Timer - PullRequest
0 голосов
/ 23 июля 2010

* Изменить: Пожалуйста, смотрите мой ответ ниже для решения.

Есть ли опасность в следующем?Я пытаюсь отследить то, что, по моему мнению, может быть расой.Я решил начать с этого и перейти оттуда.

private BlockingCollection<MyTaskType>_MainQ = new BlockingCollection<MyTaskType>();
private void Start()
{
  _CheckTask = new Timer(new TimerCallback(CheckTasks), null, 10, 5000);
}

private void CheckTasks(object state)
{
  _CheckTask.Change(Timeout.Infinite, Timeout.Infinite);
  GetTask();
  _CheckTask.Change(5000,5000);
}

private void GetTask()
{
  //get task from database to object
  Task.Factory.StartNew( delegate {
    AddToWorkQueue(); //this adds to _MainQ which is a BlockingCollection
  });
}

private void AddToWorkQueue()
{
  //do some stuff to get stuff to move
  _MainQ.Add(dataobject);
}

edit: я также использую статический класс для обработки записи в базу данных.Каждый вызов должен иметь свои собственные уникальные данные, вызываемые из множества потоков, поэтому он не разделяет данные.Как вы думаете, это может быть источником раздора?

Код ниже:

public static void ExecuteNonQuery(string connectionString, string sql, CommandType commandType, List<FastSqlParam> paramCollection = null, int timeout = 60)
{
  //Console.WriteLine("{0} [Thread {1}] called ExecuteNonQuery", DateTime.Now.ToString("HH:mm:ss:ffffff"), System.Threading.Thread.CurrentThread.ManagedThreadId);
  using (SqlConnection connection = new SqlConnection(connectionString))
  using (SqlCommand command = new SqlCommand(sql, connection))
  {
    try
    {
      if (paramCollection != null)
      {
        foreach (FastSqlParam fsqlParam in paramCollection)
        {
          try
          {
            SqlParameter param = new SqlParameter();
            param.Direction = fsqlParam.ParamDirection;
            param.Value = fsqlParam.ParamValue;
            param.ParameterName = fsqlParam.ParamName;
            param.SqlDbType = fsqlParam.ParamType;
            command.Parameters.Add(param);
          }
          catch (ArgumentNullException anx)
          {
            throw new Exception("Parameter value was null", anx);
          }
          catch (InvalidCastException icx)
          {
            throw new Exception("Could not cast parameter value", icx);
          }
        }
      }

      connection.Open();
      command.CommandType = commandType;
      command.CommandTimeout = timeout;
      command.ExecuteNonQuery();

      if (paramCollection != null)
      {
        foreach (FastSqlParam fsqlParam in paramCollection)
        {
          if (fsqlParam.ParamDirection == ParameterDirection.InputOutput || fsqlParam.ParamDirection == ParameterDirection.Output)
            try
            {
              fsqlParam.ParamValue = command.Parameters[fsqlParam.ParamName].Value;
            }
            catch (ArgumentNullException anx)
            {
              throw new Exception("Output parameter value was null", anx);
            }
            catch (InvalidCastException icx)
            {
              throw new Exception("Could not cast parameter value", icx);
            }
        }
      }
    }
    catch (SqlException ex)
    {
      throw ex;
    }
    catch (ArgumentException ex)
    {
      throw ex;
    }
  }
}

за запрос:

FastSql.ExecuteNonQuery(connectionString, "someProc", System.Data.CommandType.StoredProcedure, new List<FastSqlParam>() { new FastSqlParam(SqlDbType.Int, "@SomeParam", variable)});

Кроме того, я хотел отметить, что этот кодКажется, что происходит сбой при случайном запуске его из VS2010 [Debug или Release].Когда я делаю сборку релиза, запускаю программу установки на dev-сервере, на котором он будет размещаться, приложение не может аварийно завершить работу и работает нормально.

на запрос:

Текущая архитектура потоков:

  1. Поток Чтение 1 записи из таблицы планирования базы данных
  2. Поток A, если возвращается строка, запускает Task для входа в систему ресурса и проверки наличия файлов.перевести.Задача ссылается на объект, который содержит данные из DataTable, который создавался с использованием статического вызова.В основном, как показано ниже.
  3. Если найдены файлы, Task добавляет в _MainQ файлы для перемещения

    //Called from Thread A
    void ProcessTask()
    {
        var parameters = new List<FastSqlParam>() { new FastSqlParam(SqlDbType.Int, "@SomeParam", variable) };
        using (DataTable someTable = FastSql.ExecuteDataTable(connectionString, "someProc", CommandType.StoredProcedure, parameters))
        {
            SomeTask task = new Task();
    
                //assign task some data from dt.Rows[0]
    
                if (task != null)
                {
                    Task.Factory.StartNew(delegate { AddFilesToQueue(task); });
                }
            }
        }
    
    void AddFilesToQueue(Task task)
    {
        //connect to remote system and build collection of files to WorkItem
        //e.g, WorkItem will have a collection of collections to transfer.  We control this throttling mechanism to allow more threads to split up the work
        _MainQ.Add(WorkItem);
    }
    

Как вы думаете, может бытьпроблема возврата значения из FastSql.ExecuteDataTable, так как это статический класс, а затем его использование с блоком using?

Ответы [ 2 ]

0 голосов
/ 31 августа 2010

Оказывается, проблема была очень, очень странной.

Я преобразовал исходное решение из решения .NET 3.5 в решение .NET 4.0. Проблема блокировки исчезла, когда я заново создал все решение в новом решении .NET 4.0. Других изменений не было, поэтому я уверен, что проблема заключалась в обновлении до 4.0.

0 голосов
/ 23 июля 2010

Лично я бы опасался вводить дополнительные темы во многих местах - «Здесь будут драконы» - это полезное правило для работы с потоками!Я не вижу никаких проблем с тем, что у вас есть, но если бы это было проще, было бы легче быть более уверенным.Я предполагаю, что вы хотите, чтобы вызов "AddToWorkQueue" выполнялся в другом потоке (для проверки состояния гонки), поэтому я оставил это в.

Делает ли это то, что вам нужно?(глаз скомпилирован, поэтому может быть ошибочным)


while(true) {
    Task.Factory.StartNew( delegate { AddToWorkQueue(); });
    Thread.Sleep(5000);
}

Случайно в стороне - предпочитайте "throw;""бросить бывшего";- первый сохраняет исходный стек вызовов, второй даст вам только номер строки «throw ex»;вызов.Более того, в этом случае не используйте try / catch, так как все, что вам нужно сделать, это перебросить исключения, так что вы также можете сэкономить накладные расходы на попытку.

...