Je pense que je devrais repenser à mon design. J'ai du mal à réduire un bug qui bloque complètement mon ordinateur, en lançant parfois un HRESULT 0x8007000E de VS 2010.Threadpool/WaitHandle ressource fuite/accident
J'ai une application de console (que je convertirai plus tard en un service) qui gère transférer des fichiers basés sur une file d'attente de base de données.
Je suis en train d'étrangler les threads autorisés à transférer. En effet, certains systèmes auxquels nous nous connectons ne peuvent contenir qu'un certain nombre de connexions de certains comptes. Par exemple, le système A ne peut accepter que 3 connexions simultanées (ce qui signifie 3 threads séparés). Chacun de ces threads possède son propre objet de connexion unique, donc nous ne devrions pas nous lancer dans des problèmes de synchronisation car ils ne partagent pas une connexion.
Nous voulons traiter les fichiers de ces systèmes par cycles. Ainsi, par exemple, nous autoriserons 3 connexions pouvant transférer jusqu'à 100 fichiers par connexion. Cela signifie que pour déplacer 1000 fichiers du système A, nous ne pouvons traiter que 300 fichiers par cycle, puisque 3 threads sont autorisés avec 100 fichiers chacun. Par conséquent, pendant la durée de ce transfert, nous aurons 10 threads. Nous pouvons seulement courir 3 à la fois. Donc, il y aura 3 cycles, et le dernier cycle utilisera seulement 1 thread pour transférer les 100 derniers fichiers. (3 fils x 100 fichiers = 300 fichiers par cycle)
L'architecture actuelle par exemple:
- Un System.Threading.Timer vérifie la file d'attente toutes les 5 secondes pour quelque chose à faire en appelant GetScheduledTask()
- S'il n'y a rien à, GetScheduledTask() ne fonctionne tout simplement S'il n'y a rien
- travail, créer un fil ThreadPool pour traiter le travail [travail discussion a]
- travail discussion a voit qu'il ya 1000 fichiers à transférer
- travail Discussion A voit qu'il ne peut avoir 3 fils en cours d'exécution sur le système, il récupèrera les bons fichiers
- travail Discussion A commence trois nouveaux fils de travail [B, C, D] et les transferts
- travail thread A attend B, C, D
[WaitHandle.WaitAll(transfersArray)]
- fil de travail a voit qu'il ya encore plus de fichiers dans la file d'attente (doit être 700 maintenant)
- travail discussion a crée un nouveau tableau d'attendre le
[transfersArray = new TransferArray[3]
qui est le maximum pour le système a, mais peut varier sur le système - Le thread de travail A démarre trois nouveaux threads de travail [B, C, D] et les attend
[WaitHandle.WaitAll(transfersArray)]
- Le processus se répète jusqu'à ce qu'il n'y ait plus de fichiers à déplacer.
- travail de la discussion des signaux A qu'il est fait
J'utilise ManualResetEvent pour gérer la signalisation.
Mes questions sont les suivantes:
- Y at-il des circonstances criantes qui provoquerait une fuite de ressources ou un problème que je ressentais?
- Si je boucle à travers le tableau après chaque
WaitHandle.WaitAll(array)
et appelezarray[index].Dispose()?
- Le nombre de handles dans le Gestionnaire des tâches de ce processus se glisse lentement
- J'appelle la création initiale de travailleurs Discussion A partir d'un System.Threading. Minuteur. Y aura-t-il des problèmes avec ça? Le code de cette temporisation est le suivant:
(Certains code de classe pour la programmation)
private ManualResetEvent _ResetEvent;
private void Start()
{
_IsAlive = true;
ManualResetEvent transferResetEvent = new ManualResetEvent(false);
//Set the scheduler timer to 5 second intervals
_ScheduledTasks = new Timer(new TimerCallback(ScheduledTasks_Tick), transferResetEvent, 200, 5000);
}
private void ScheduledTasks_Tick(object state)
{
ManualResetEvent resetEvent = null;
try
{
resetEvent = (ManualResetEvent)state;
//Block timer until GetScheduledTasks() finishes
_ScheduledTasks.Change(Timeout.Infinite, Timeout.Infinite);
GetScheduledTasks();
}
finally
{
_ScheduledTasks.Change(5000, 5000);
Console.WriteLine("{0} [Main] GetScheduledTasks() finished", DateTime.Now.ToString("MMddyy HH:mm:ss:fff"));
resetEvent.Set();
}
}
private void GetScheduledTask()
{
try
{
//Check to see if the database connection is still up
if (!_IsAlive)
{
//Handle
_ConnectionLostNotification = true;
return;
}
//Get scheduled records from the database
ISchedulerTask task = null;
using (DataTable dt = FastSql.ExecuteDataTable(
_ConnectionString, "hidden for security", System.Data.CommandType.StoredProcedure,
new List<FastSqlParam>() { new FastSqlParam(ParameterDirection.Input, SqlDbType.VarChar, "@ProcessMachineName", Environment.MachineName) })) //call to static class
{
if (dt != null)
{
if (dt.Rows.Count == 1)
{ //Only 1 row is allowed
DataRow dr = dt.Rows[0];
//Get task information
TransferParam.TaskType taskType = (TransferParam.TaskType)Enum.Parse(typeof(TransferParam.TaskType), dr["TaskTypeId"].ToString());
task = ScheduledTaskFactory.CreateScheduledTask(taskType);
task.Description = dr["Description"].ToString();
task.IsEnabled = (bool)dr["IsEnabled"];
task.IsProcessing = (bool)dr["IsProcessing"];
task.IsManualLaunch = (bool)dr["IsManualLaunch"];
task.ProcessMachineName = dr["ProcessMachineName"].ToString();
task.NextRun = (DateTime)dr["NextRun"];
task.PostProcessNotification = (bool)dr["NotifyPostProcess"];
task.PreProcessNotification = (bool)dr["NotifyPreProcess"];
task.Priority = (TransferParam.Priority)Enum.Parse(typeof(TransferParam.SystemType), dr["PriorityId"].ToString());
task.SleepMinutes = (int)dr["SleepMinutes"];
task.ScheduleId = (int)dr["ScheduleId"];
task.CurrentRuns = (int)dr["CurrentRuns"];
task.TotalRuns = (int)dr["TotalRuns"];
SchedulerTask scheduledTask = new SchedulerTask(new ManualResetEvent(false), task);
//Queue up task to worker thread and start
ThreadPool.QueueUserWorkItem(new WaitCallback(this.ThreadProc), scheduledTask);
}
}
}
}
catch (Exception ex)
{
//Handle
}
}
private void ThreadProc(object taskObject)
{
SchedulerTask task = (SchedulerTask)taskObject;
ScheduledTaskEngine engine = null;
try
{
engine = SchedulerTaskEngineFactory.CreateTaskEngine(task.Task, _ConnectionString);
engine.StartTask(task.Task);
}
catch (Exception ex)
{
//Handle
}
finally
{
task.TaskResetEvent.Set();
task.TaskResetEvent.Dispose();
}
}
On dirait que c'était une erreur de codage liée à la déclaration du tableau des événements de réinitialisation. Je faisais 'ManualResetEvent [] = new événements ManualResetEvents [count];' au lieu de 'WaitHandle [] = new événements WaitHandle [count]' –