Cómo atrapar excepciones de un ThreadPool.QueueUserWorkItem?
Tengo el siguiente código que lanza una excepción:
ThreadPool.QueueUserWorkItem(state => action());
Cuando la acción lanza una excepción, mi programa se bloquea. ¿Cuál es la mejor práctica para manejar esta situación?
Relacionado: Excepciones en los subprocesos. Net ThreadPool
5 answers
Si tiene acceso al código fuente de action
, inserte un bloque try/catch en ese método; de lo contrario, cree un nuevo método tryAction
que envuelva la llamada a action
en un bloque try/catch.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 21:41:50
Puedes añadir try / catch así:
ThreadPool.QueueUserWorkItem(state =>
{
try
{
action();
}
catch (Exception ex)
{
OnException(ex);
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 21:43:34
Si está utilizando.Net 4.0, podría valer la pena investigar la clase Task porque puede encargarse de esto por usted.
El equivalente de su código original, pero usando Tareas, se ve como
Task.Factory.StartNew(state => action(), state);
Para lidiar con las excepciones, puede agregar una continuación a la Tarea devuelta por StartNew. Podría verse así:
var task = Task.Factory.StartNew(state => action(), state);
task.ContinueWith(t =>
{
var exception = t.Exception.InnerException;
// handle the exception here
// (note that we access InnerException, because tasks always wrap
// exceptions in an AggregateException)
},
TaskContinuationOptions.OnlyOnFaulted);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 18:51:07
En el otro hilo, (en el método "colas", se agrega una cláusula try catch... .Luego, en catch, coloque la excepción captada en una variable de excepción compartida (visible para el hilo principal).
Luego, en su subproceso principal, cuando todos los elementos en cola hayan terminado (use una matriz de manejadores de espera para esto) Verifique si algún subproceso llenó esa excepción compartida con una excepción... Si lo hizo, repensarlo o manejarlo como corresponda...
Aquí hay un código de ejemplo de un proyecto reciente I usé esto para...
HasException es booleano compartido...
private void CompleteAndQueuePayLoads(
IEnumerable<UsagePayload> payLoads, string processId)
{
List<WaitHandle> waitHndls = new List<WaitHandle>();
int defaultMaxwrkrThreads, defaultmaxIOThreads;
ThreadPool.GetMaxThreads(out defaultMaxwrkrThreads,
out defaultmaxIOThreads);
ThreadPool.SetMaxThreads(
MDMImportConfig.MAXCONCURRENTIEEUSAGEREQUESTS,
defaultmaxIOThreads);
int qryNo = 0;
foreach (UsagePayload uPL in payLoads)
{
ManualResetEvent txEvnt = new ManualResetEvent(false);
UsagePayload uPL1 = uPL;
int qryNo1 = ++qryNo;
ThreadPool.QueueUserWorkItem(
delegate
{
try
{
Thread.CurrentThread.Name = processId +
"." + qryNo1;
if (!HasException && !uPL1.IsComplete)
IEEDAL.GetPayloadReadings(uPL1,
processId, qryNo1);
if (!HasException)
UsageCache.PersistPayload(uPL1);
if (!HasException)
SavePayLoadToProcessQueueFolder(
uPL1, processId, qryNo1);
}
catch (MeterUsageImportException iX)
{
log.Write(log.Level.Error,
"Delegate failed " iX.Message, iX);
lock (locker)
{
HasException = true;
X = iX;
foreach (ManualResetEvent
txEvt in waitHndls)
txEvt.Set();
}
}
finally { lock(locker) txEvnt.Set(); }
});
waitHndls.Add(txEvnt);
}
util.WaitAll(waitHndls.ToArray());
ThreadPool.SetMaxThreads(defaultMaxwrkrThreads,
defaultmaxIOThreads);
lock (locker) if (X != null) throw X;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 21:49:09
Lo que suelo hacer es crear un gran intento ... bloque catch dentro del método action() a continuación, almacenar la excepción como una variable privada y luego manejarla dentro del hilo principal
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 21:41:12