2012-09-12 26 views
5

Tengo un código que tengo actualmente en una clase/método estático, pero quería comprobar que sería seguro para subprocesos. Por lo que he leído, creo que esto debería estar bien, pero algo en el fondo de mi mente es decir que podría no serlo. La etapa de procesamiento de datos de mi página web usa un servicio web externo para crear registros de pedidos, y esto podría ser bastante lento: posiblemente entre 30 y 40 segundos, posiblemente, 5 o 10 minutos (esto está fuera de mi alcance), así que iba a disparar una página de retorno al usuario, luego comience un nuevo hilo y luego envíe un correo electrónico al usuario una vez que se complete el proceso. Esto se encuentra actualmente en una clase/método estático. Siempre que todos mis objetos se creen dentro del método particular (aparte de los valores predeterminados del sistema, que serían comunes), ese método debería ser seguro para subprocesos, ¿no es así? Así, por ejemplo, si tuvieraAsegurando la seguridad del hilo en métodos estáticos En C#

public static class ProcessOrder() 
{ 
    public static int GetOrderMaxSize() 
    { 
     return (....gets and parses ConfigurationManager.AppSettings["MaxOrderSize"]...); 
    } 

    public static bool CreateOrder(Order order) 
    { 
     XmlDocument xmlDoc = GetOrderXML(order); 
     bool check = false; 
     using (CreateOrderXML.Create xmlCo = new CreateOrderXML.Create()) 
     { 
      xmlCo.Timeout = 60000; 
      System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 

      string xmlString = ""; 
      using (StringWriter stringWriter = new StringWriter()) 
      { 
       using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter)) 
       { 
        xmlDoc.WriteTo(xmlWriter); 
        xmlWriter.Flush(); 
        xmlString = stringWriter.GetStringBuilder().ToString(); 
       } 
      } 

      byte[] bXMLOrder = encoding.GetBytes(xmlString); 
      byte[] breturnMessage; 

      check = xmlCo.Create(bXMLOrder, out breturnMessage); 
      .... do something with return message 
     } 
     return check; 
    } 

    private static XmlDocument GetOrderXML(Order order) 
    { 
     ... creates an XML object for the order 
    } 
} 

(el CreateOrderXML es una referencia de servicio a la URL del servicio Web/método) habría que ser flujos seguros, especialmente para los de larga duración (principalmente en el xmlCo.Create (....) etapa) hilos concurrentes? Entiendo que si comencé a incluir miembros en la clase y luego los usé en el método, esto definitivamente generaría un problema con diferentes hilos que sobreescriban los valores, pero siempre que los objetos sean creados dentro de los métodos, deberían estar bien, no deberían ' t ellos?

Respuesta

12

Parece que no está accediendo a ningún dato compartido allí; está solicitando recursos remotos y creando un conjunto único de datos con cada ejecución de este método. No hay necesidad de sincronización allí.

Cada ejecución del método aquí está creando variables locales: sus propias copias. Por lo tanto, nunca se comparte nada.

+0

las variables Sí, a propósito sólo he utilizado "de todo el sistema por defecto" en la propia clase, y paso todo en lo que se requiere para el procesamiento que pueden ser específicas para el usuario/sesión a través de los parámetros del método. Pero todavía tenía zumbidos de advertencia en la parte posterior de mi cabeza, ojalá sean solo "paranoia saludable". –

+0

¡Me suena a paranoia saludable! –

5

Si su método estático no accede a ningún dato estático (de clase), debe ser seguro para subprocesos. Los únicos puntos posibles de contención serían los recursos externos que podría usar (archivos, por ejemplo, u otros recursos del sistema) y los datos que se transfieren. Y solo usted conoce el contexto de ese tipo de uso.

El uso de elementos como los que podrían estar en disputa se puede serializar con lock u otras primativas. No te olvides de serializar los recursos en el mismo orden para que no te lleves a un punto muerto. Si usted tiene un método que utiliza el recurso A y B:

lock(latch_a) 
{ 
    process(object_a) ; 
    lock (latch_b) 
    { 
    process(object_a,object_b) ; 
    } 
} 

y otro método que hace el inverso:

lock(latch_b) 
{ 
    process(object_b) ; 
    lock (latch_a) 
    { 
    process(object_a,object_b) ; 
    } 
} 

En algún momento de sus dos hilos se callejón sin salida, cuando cada uno de ellos requiere un recurso el otro necesita antes de poder renunciar al acceso a dicho recurso.

Editado tener en cuenta: Consulte la documentación de C# para la declaración lock para más detalles. En general, el objeto bloqueado representa (y podría ser) el acceso a recursos compartidos al que se está serializando. Un patrón común es hacer algo como:

class Widget 
{ 
    private static readonly object X = new object() ; 

    public void Foo() 
    { 
    lock(X) 
    { 
     // Do work using shared resource 
    } 
    return ; 
    } 

} 
+0

¿Los objetos latch_a y latch_b se deben crear una vez y luego pasar a cada llamada al método estático? – Doug

+0

@Doug: Vea mi respuesta enmendada. –