C# Funktionen in verschiedenen Objekten blokieren

dapcfreek

Lieutenant
Registriert
Okt. 2008
Beiträge
813
Hallo an alle C#-Profis,

ich programmiere jetzt doch schon eine Weile in C# und konnte mir eigentlich immer helfen, aber bei dem Problem bin ich total überfragt, also hoffe ich, dass Ihr mir da helfen könnt.

Also, ich habe zwei voneinander komplett unabhängige Objekte, die auch voneinander unabhängig aufgerufen werden müssen. In beiden Objekten habe ich jeweils einen Timer, der eine Funktion aufruft, die einen bestimmten Datenbankzugriff über das Entity-Framwork durchführt. Es kommt ganz selten vor, dass der eine Timer aufgerufen ist und der andere zur gleichen Zeit aufgerufen wird. Aber leider kommt es doch hin und wieder vor, dabei steigt dann das Programm beim Datenbankzugriff aus.

Jetzt versuche ich eine Lösung zu finden. Es währe super, wenn mir hier jemand weiterhelfen kann. Am liebsten währe es mir, wenn ich die Timer gegenseitig blokieren kann.

Gruß
dapcfreek
 
Unabhängig der Sprache hätte ich jetzt einen Proxy implementiert, der die Zugriffssteuerung regelt - bzw. eine Semaphore könnte auch Abhilfe schaffen. Damit beschränkst du den Zugriff auf die DB auf maximal 1 Verbindung in deinem Fall, falls das tatsächlich die Ursache sein sollte...
 
Ok, danke, sowas in der Art hätte ich mir vorgestellt. Werde mich mal in das einlesen.
Denkst du, das hat einen anderen Grund?
 
Der Datenbankzugriff mus inerhalb eines kritischen Abschnitts erfolgen. Die bereits genannten Semaphoren sind dafür gedacht einen solchen Abschnitt zu definieren.
 
Wäre ein Mutex nicht besser? Die Timer machen die Signale der Semaphoren ja quasi überflüssig.
 
Man könnte einfach eine statische bool-variable verwenden und diese in beiden Timern abfragen und setzen. Also quasi als eine Art locking-objekt. Am besten in der Program.cs

public static volatile bool db_lock;

oder so.
 
DocWindows schrieb:
Man könnte einfach eine statische bool-variable verwenden und diese in beiden Timern abfragen und setzen. Also quasi als eine Art locking-objekt. Am besten in der Program.cs

public static volatile bool db_lock;

oder so.

Das ist keine gute Idee, da das setzen dieser Variable nicht atomar ist. Es kann trotzdem zu Race Conditions kommen.
 
bad_influence schrieb:
Wäre ein Mutex nicht besser?
Jap, würde ich auch sagen.

DocWindows schrieb:
Man könnte einfach eine statische bool-variable verwenden und diese in beiden Timern abfragen und setzen.
Das ist aber nicht threadsafe!

Code:
if(isResourceAvailable)
{
     // wenn an dieser Stelle ein anderer Thread isResourceAvailable abfragt,
     // hat die Variable immernoch den Wert true. Race Condition!

     isResourceAvailable = false;
}

Edit: blackst0rm war schneller
 
Jepp auch der Zugriff auf den Bool muss Threadsafe erfolgen. Ein einfacher lock auf ein Objekt würde es doch tun, wenn beide DB Operationen ausgeführt werden sollen.
 
Wenn man die Timer gegenseitig blockieren will, die ja nichts voneinander wissen, dann wäre das über eine statische Variable lösbar.
Man muss sie ja nicht im unbedingt direkt ansprechen. Man könnte die Variable auch privat machen und eine öffentliche Funktion schreiben in der dann ein lock verwendet wird.

Ansonsten führt wirklich kein Weg daran vorbei die Datenbankzugriffe auszulagern und über eine eigene threadsichere Klasse durchzuführen.

Naja, viele Wege führen nach Rom ;)
 
DocWindows schrieb:
Wenn man die Timer gegenseitig blockieren will, die ja nichts voneinander wissen, dann wäre das über eine statische Variable lösbar.
Man muss sie ja nicht im unbedingt direkt ansprechen. Man könnte die Variable auch privat machen und eine öffentliche Funktion schreiben in der dann ein lock verwendet wird.

Ansonsten führt wirklich kein Weg daran vorbei die Datenbankzugriffe auszulagern und über eine eigene threadsichere Klasse durchzuführen.

Naja, viele Wege führen nach Rom ;)

Dann kannst du aber auch gleich den Datenbankzugriff locken. Is meiner Meinung nach auch die bessere Lösung, da dadurch die Intention des Locks deutlich zu erkennen ist.
 
DocWindows schrieb:
Man muss sie ja nicht im unbedingt direkt ansprechen. Man könnte die Variable auch privat machen und eine öffentliche Funktion schreiben in der dann ein lock verwendet wird.
Aber dann kannst du die bool Variable auch gleich weglassen und einfach ein globales statisches Objekt nutzen, auf das du locken kannst.

Der einfachste Weg wäre wohl, einfach ne Proxy-Klasse zu schreiben die den Datenbankzugriff regelt.
Die Synchronisation könnte dann einfach durch ein privates statisches Objekt der Proxy-Klasse erfolgen, auf das gelockt wird.

Also quasi sowas:
Code:
pubic class DbProxy
{
    private static object syncRoot = new object();

    public object GetData()
    {
        lock(syncRoot)
        {
            return GetDataFromDb();
        }
    }
    
    private object GetDataFromDb()
    {
        throw new NotImplementedException();
    }
}
 
Die primäre Frage war aber wie man 2 Timer blockieren kann die nichts voneinander wissen.

Den Datenbankzugriff auszulagern ist sowieso immer eine gute Idee, auch wenn man nicht vor diesem Problem steht.
Ist einfach übersichtlicher und man hat alles beisammen was zusammen gehört. Ist bei Änderungen sehr praktisch oder wenn man das ganze Datenbanksystem wechseln oder durch ein alternatives Datenbanksystem ergänzen will.
 
Zurück
Oben