1

Wir haben eine Client Klasse, die eine BaseClass erweitert.Wie kann man diesen Wettlauf verhindern?

Die Baseclass hat diese Methoden:

protected void Proxy() 
    { 
     Error = null; 
     _proxy = new WebServiceClient<T>(_fullURL); 
     Error = _proxy.Error; 
    } 

    protected virtual void Cleanup() 
    { 
     if (_proxy != null) 
     { 
      _proxy.Dispose(); 
      _proxy = null; 
     } 
    } 

Und der Kunde enthält mehrere Operationen, die parallel aufgerufen werden. Client ist kein Singleton, wir erzeugen jedes Mal eine Instanz.

Die Operationen sind wie:

public void OperationAsync(Action<BaseResult> callback) 
{ 

    TaskCompletionSource<String> taskSrc = new TaskCompletionSource<String>(); 
    Task<String> tsk = taskSrc.Task; 
    try 
    { 
     Proxy(); 

     ThreadPool.QueueUserWorkItem(t => 
     { 
      try 
      { 
       String result = _proxy.Channel.ExecuteOperation(SecurityToken()); 
       taskSrc.SetResult(result); 
      } 
      catch (Exception ex) 
      { 
       taskSrc.SetException(ex); 
      } 
     }); 

     tsk.Wait(); 

     BaseResult r = new BaseResult(); 
     r.Value = tsk.Result; 
     r.Error = tsk.Exception; 
     Cleanup(); 

     if (callback != null) 
     { 
      callback(r); 
     } 

    } 
    catch (Exception ex) 
    { 
     FileManager.Log(ex); 
    } 
} 

Wie Sie sehen können, jede Operation ruft die Proxy und CleanUp Operationen.

Wir fanden keine Verhaltensmuster entdecken hat noch nicht, aber manchmal (vielleicht einmal am Tag) wir diesen Fehler in der Protokolldatei finden Sie unter:

mindestens ein Fehler aufgetreten .. Innerexception: System.ObjectDisposedException: Kann nicht Zugriff auf ein entsorgtes Objekt. Objektname: 'System.ServiceModel.Channels.ServiceChannel'.

Es passiert nicht bei einer bestimmten Operation. Es variiert alle Zeiten. Ich glaube, dass der Proxy während des Konstruktors und der CleanUp während der Entsorgung durchgeführt werden muss, aber es bedeutet, dass mehrere Dinge geändert werden, und ich möchte sicher sein.

Ich würde wirklich jede Idee schätzen, wie es verbessern kann.

+1

Warum überhaupt ein Feld 'ist _proxy'? Warum nicht 'Proxy' ein' WebServiceClient 'zurückgeben, speichern Sie es in einer Variablen, die lokal zur Funktion ist, dann geben Sie diese Variable an' Cleanup' ein. Ihr Hintergrund-Worker tut nichts anderes, als zusätzlichen Overhead zu Ihrem Funktionsaufruf hinzuzufügen. Wenn Sie einen anderen Thread bearbeiten wollen, rufen Sie sofort '.Wait()' auf, damit dieser Thread beendet wird, und Sie werden immer schlechter arbeiten, wenn Sie keinen zusätzlichen Thread verwenden. –

+1

Sie müssen wirklich aufhören zu schreiben 'catch (Exception ex)' in Ihrem Code. Es bringt nur Bugs. Sie sollten immer nur Ausnahmen abfangen, von denen Sie wiederherstellen können und die außergewöhnlich sind. Lesen Sie [Eric Lipperts Vexing Exceptions] (https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/). – Enigmativity

+0

Um hier eine Race-Bedingung zu bekommen, müssen Sie entweder OperationAsync mehrmals auf derselben Instanz aufrufen (was Sie nicht gemäß Ihren Anweisungen tun), oder _proxy als statisches Member haben (Sie haben die Definition nicht angezeigt) Feld). Ich nehme an, dass die Race-Bedingung tatsächlich eine andere Ursache in Code hat, den Sie nicht angezeigt haben (d. H., Sie rufen OperationAsync mehr als einmal für eine einzelne Instanz auf). –

Antwort

1

Da der ursprüngliche Code tsk.Wait(); aufgerufen hat, blockierten Sie den aufrufenden Thread, während Sie Ihren Proxy-Code auf einem Hintergrundthread ausführen. Es gibt keinen Vorteil und wahrscheinlich erhöhte Kosten, die es so machen.

So, hier ist, wie die Race-Bedingung zu verhindern:

public void OperationAsync(Action<BaseResult> callback) 
{ 
    try 
    { 
     var r = new BaseResult(); 
     using (var proxy = new WebServiceClient<T>(_fullURL)) 
     { 
      try 
      { 
       r.Value = proxy.Channel.ExecuteOperation(SecurityToken()); 
      } 
      catch (Exception ex) 
      { 
       r.Error = ex; 
      } 
     } 
     if (callback != null) 
     { 
      callback(r); 
     } 
    } 
    catch (Exception ex) 
    { 
     FileManager.Log(ex); 
    } 
} 
Verwandte Themen