* Редактирование: см. Мой ответ ниже для решения.Задание, запущенное с Threading.Timer
Есть ли опасность в следующем? Я пытаюсь отследить, что, по моему мнению, может быть условием гонки. Я решил, что начну с этого и уйду оттуда.
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);
}
Редактировать: Я также использую статический класс для обработки записи в базу данных. Каждый вызов должен иметь свои собственные уникальные данные, вызываемые из многих потоков, поэтому он не использует данные. Считаете ли вы, что это может быть источником раздора?
код ниже:
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]. Когда я делаю сборку релизов, запустите настройку на сервере-разработчике, который будет ее размещать, приложение не сработало и работает бесперебойно.
по запросу:
Текущая архитектура потоков:
- Нитки чтение 1 запись из таблицы планирования базы данных
- Thread А, если строка возвращается, запускает
Task
для входа в ресурс, чтобы посмотреть, есть ли файлы для передачи. Задача ссылается на объект, который содержит данные изDataTable
, которые создавались с использованием статического вызова. В принципе, как показано ниже. Если файлы найдены,
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
?
Можете ли вы опубликовать фрагмент кода, который вызывает 'Take' в очереди? Также полезно будет показывать, когда вызывается вызов ExecuteNonQuery. –
Извините, я был не очень ясен. Я действительно хотел увидеть код, который показывает, какой поток выполняется 'ExecuteNonQuery'. Я предполагаю, что это тот же самый поток, который называет 'Take'. Если это так, у вас есть как минимум 3 потока в игре здесь 1) тот, который вызывает 'Add' 2) сам таймер обратного вызова 3), и тот, который вызывает' Take'. Полное представление о том, как потоки взаимодействуют, является единственным верным способом определения любого возможного состояния гонки. –
Нет, я не думаю, что это связано с возвратом 'FastSql.ExecuteDataTable', являющегося целью' use'. Я до сих пор не вижу, где вызывается метод BlockingCollection.Take. –