Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Threadsicher auf eine Abfrage zugreifen
padde77
myCSharp.de - Member



Dabei seit:
Beiträge: 50

Themenstarter:

Threadsicher auf eine Abfrage zugreifen

beantworten | zitieren | melden

Hi,

ich habe eine Methode A, welche mir einen Ergebnisdatensatz zurück liefert, und zwar anhand eines Parameters. Diese Methode wird jedoch von verschiedenen Threads aufgerufen,
Thread 1 -> Methode A(1)
Thread 2 -> Methode A(2)
...

Mein Problem ist nur, dass in der Methode eine Abfrage auf eine DLL statt findet, und diese kommt nur mit einer gleichzeitigen Verbindung klar. Also kann müsste die Abfrage des 2., 3. usw. erst auf das Ergebnis des ersten Aufrufes warten.
Wie kann ich dies am besten bewerkstelligen?

Ein kleines Snippet wäre auch nett.

Danke Patrick
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1833
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

Stichwort ist hier Thread Locking.
Kannst du mit dem Keyword lock und einem entsprechenden Locking Objekt erledigen.
Musst dann natürlich den Aufruf der DLL Methode am besten kapseln und dann über deine Methode mit dem Lock aufrufen.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1476
Herkunft: Düsseldorf

beantworten | zitieren | melden

Den Aufruf selber kannst Du zwar threadsafe gestalten, aber ich würde es nicht machen.
Besser ist, wenn die Methode von sich aus threadsafe ist und sich darum kümmert, das nur ein Thread gleichzeitig auf die DLL zugreifen kann.
So kannst Du beim Aufruf nix falsch machen.

Und wie das geht: lock
Das kann genau das, was Du haben willst.
private Nachricht | Beiträge des Benutzers
padde77
myCSharp.de - Member



Dabei seit:
Beiträge: 50

Themenstarter:

beantworten | zitieren | melden

OK, ich werde mir das einmal ansehen.
Lock heisst dann, dass sich Thread 4, 8 und 9 hinten anstellen müssen, bis z.B. Thread 2 seine Rückgabe hat und die Methode sagt: "der nächste bitte". Korrekt?

Danke und Gruß
Patrick
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1476
Herkunft: Düsseldorf

beantworten | zitieren | melden

So ungefähr, ja.

Das übergebene Objekt dient dabei als eine Art Schlüssel, Typ ist dabei egal.
Wichtig ist nur, dass die Instanz immer die Gleiche ist.
private Nachricht | Beiträge des Benutzers
padde77
myCSharp.de - Member



Dabei seit:
Beiträge: 50

Themenstarter:

beantworten | zitieren | melden

...noch eine kurze Frage:

kann ich innerhalb eines locks eine andere Method mit Rückgabe aufrufen und wartet das lock trotzdem?
Kann leider nicht testen, da ich heute keine Testumgebung hier habe, daher die Frage, sorry.

also so:

lock(obj)
{
    var test = NeueMethode(parameter);
}

Vielen Dank
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von padde77 am .
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1833
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@padde77
Kannst du.
Du kannst auch eine weitere Methode, die ein Lock hat aufrufen.
Dann muss aber ggf. der Aufruf von dir auch auf andere Threads, die gerade diese Methode aufrufen, warten müssen.

Kannst du aber auch mal etwas rumtesten, dann kannst du das Verhalten nachvollziehen.
Gerade um auf geteilte Resourcen zuzugreifen, solltest du dich mit dem Thema gut beschäftigen.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15806
Herkunft: BW

beantworten | zitieren | melden

Bevor man direkt irgendwas mit Threads wurschtelt, sollte man mal schauen, ob es nicht einen Pattern gibt, mit dem man das Vorhaben strukturiert umsetzen kann.

Hier scheint es ja auch irgendein Logik- oder Datenteil zu betreffen, für das es in den meisten Fällen passende Pattern gibt.
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1833
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@Abt
Sollte eigentlich logisch sein.
Aber gerade da der TE scheinbar noch ein Defizit bei dem Thema Threads hat, sollte er mit einem Testprogramm mal rumspielen und sich durch die Doku lesen um das entsprechende Wissen aufzubauen.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15806
Herkunft: BW

beantworten | zitieren | melden

Ja aber das hier hört sich nicht nach einem Testprogramm an.

Und Pattern sind auch für Anfänger geeignet.
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1476
Herkunft: Düsseldorf

beantworten | zitieren | melden

@padde77:

Du solltest dir auch mal das Wort Deadlock anschauen, einer der Fehler, den wahrscheinlich jeder Entwickler beim Thema Multithreading fürchtet :D
Wie der Name sich zusammen setzt, kannst Du dir vielleicht selber erklären :D

Code-Beispiel:

Console.WriteLine("before lock 1");

lock (syncRoot)
{
    Console.WriteLine("in lock 1");

    Console.WriteLine("create thread");

    var thread = new Thread(() =>
    {
        Console.WriteLine("before lock 2");

        lock (syncRoot)
            Console.WriteLine("in lock 2");

        Console.WriteLine("thread ready");
    });

    Console.WriteLine("start thread");
    thread.Start();

    Console.WriteLine("wait for thread");
    thread.Join();
}

Console.WriteLine("ready");

Führ das mal aus, Du wirst fest stellen, dass der Code nie zu einem Ende kommt.

Der Grund ist:
Der Main-Thread läuft in das lock rein.
Er startet einen Thread, der ebenfalls ein lock auf das selbe Objekt enthält.
Anschließend wartet er auf diesen Thread.

Das Problem:
Der Main-Thread blockiert das Objekt für sich.
Der zweite Thread wartet nun darauf, dass das Objekt wieder frei wird.
Der Main-Thread wartet auf den zweiten Thread und gibt danach dann das Objekt wieder frei.
Blöd ist nur, dass das Objekt nie frei wird, bevor der Thread nicht beendet ist. Und der Thread wird nie beendet bevor er zuende ist, weil der Main-Thread das Objekt vorher nicht frei gibt.

Du erkennst das Problem? ^^
private Nachricht | Beiträge des Benutzers
padde77
myCSharp.de - Member



Dabei seit:
Beiträge: 50

Themenstarter:

beantworten | zitieren | melden

Hi, ja, danke für eure Antworten.
Das mit dem Deadlock ist klar. und das mit den Patterns schaue ich mir mal an.

Danke für eure Informationen

Grüße
Patrick
private Nachricht | Beiträge des Benutzers
Argbeil
myCSharp.de - Member



Dabei seit:
Beiträge: 5

beantworten | zitieren | melden

Das mit dem lock() funktioniert übrigens bei Calls aus async/await heraus nicht mehr.
private Nachricht | Beiträge des Benutzers
Blaster
myCSharp.de - Member



Dabei seit:
Beiträge: 75

beantworten | zitieren | melden

Singleton bilden:
Singleton (Entwurfsmuster)

using System;
using System.Reflection;
using System.Windows.Controls;

namespace XXXXXX
{
    public abstract class SingletonReflectionConstruct<T>
    {
        public static T Instance
        {
            get
            {
                return SingletonFactory.Instance;
            }
        }

        internal static class SingletonFactory
        {
            internal static T Instance;

            static SingletonFactory()
            {
                CreateInstance(typeof(T));
            }

            public static T CreateInstance(Type type)
            {
                ConstructorInfo[] ctorsPublic = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public);

                if (ctorsPublic.Length > 0)
                {
                    throw new Exception(string.Concat(type.FullName, " has one or more public constructors so the property cannot be enforced."));
                }

                ConstructorInfo nonPublicConstructor =
                    type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], new ParameterModifier[0]);

                if (nonPublicConstructor == null)
                {
                    throw new Exception(string.Concat(type.FullName, " does not have a private/protected constructor so the property cannot be enforced."));
                }

                try
                {
                    return Instance = (T)nonPublicConstructor.Invoke(new object[0]);
                }
                catch (Exception e)
                {
                    throw new Exception(
                        string.Concat("The Singleton could not be constructed. Check if ", type.FullName, " has a default constructor."), e);
                }
            }
        }
    }

    public class BuildCanvas_Singleton : SingletonReflectionConstruct<BuildCanvas_Singleton>
    {
        private BuildCanvas_Singleton()
        {
            _canvas1 = new Canvas();
            _count++;

        }

        // Instance counter.
        private static int _count = 0;
        private static Canvas _canvas1;

        public static int Count { get { return _count; } }
        public static Canvas GetCanvas { get { return _canvas1; } }
    }
}

Die Implementierungen des zu testenen Code.


        BuildCanvas_Singleton singleton1 = BuildCanvas_Singleton.Instance;

        public Canvas canvas1 = BuildCanvas_Singleton.GetCanvas;
        public Canvas canvas2 = BuildCanvas_Singleton.GetCanvas;

evtuell mit null object:
Nullobjekt (Entwurfsmuster)
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von Blaster am .
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 996

beantworten | zitieren | melden

Zitat von Blaster
Threadsicher := Singleton bilden
Kannst du das bitte einmal erläutern, warum das deiner Meinung nach so sein sollte?

Ich halte diese Aussage für groben Unfug, bin aber nicht lern-/beratungs-resistent
private Nachricht | Beiträge des Benutzers
Blaster
myCSharp.de - Member



Dabei seit:
Beiträge: 75

beantworten | zitieren | melden

Ok! -Gebe ich dir Recht. Zu pauschal.

Grüße
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 996

beantworten | zitieren | melden

Und wie hilft jetzt so ein Singleton dem TE?

Ich sehe da bislang keinen Zusammenhang.
private Nachricht | Beiträge des Benutzers
Blaster
myCSharp.de - Member



Dabei seit:
Beiträge: 75

beantworten | zitieren | melden

Was?
Du bildest ein Singleton durch die Fabrik mit Methode A.

 public class Methode_A_Singleton : SingletonReflectionConstruct<Methode_A_Singleton>
{
      // .... Hier Schreibst Du das Threadhandling der Clients rein, die alle aktiv sein müssen.
      //  ... evt. Shunts, Hubs oder Mocks (s.u.)
}

So ruft jeder einzelne Thread die selbe Instanz von Methode A auf.
Am Besten über ein Nullobject, damit wenn ein Thread beendet wird (Dispatcher), wir noch weiterhin eine gültige Referenz für das Singleton und die anderen Threads haben.

Was mir auch noch einfällt wäre Threadaufrufe zu mockeo. o.ä. (s. Shunt, Hubs und Mocks)

Was erwartest Du? Das ich bei der abstrakten Form Meter von Code schreibe?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Blaster am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15806
Herkunft: BW

beantworten | zitieren | melden

Genau so ein Konstrukt führt aber dazu, dass Race Conditions entstehen (können) und das Debugging unheimlich aufwändig und teuer wird, sollte mal was sein.

Singleton ist hier für mich die falsche Herangehensweise.
Da wäre eine entsprechendes Messaging in meinen Augen (zB Pipelining) leistungsfähiger, übersichtlicher und am Ende besser.
private Nachricht | Beiträge des Benutzers
Blaster
myCSharp.de - Member



Dabei seit:
Beiträge: 75

beantworten | zitieren | melden

Ist genauso theoretisch falsch, weil man nicht weiß, was die Dll macht, noch was er mit den Threadaufrufen bewirken will.

Racing constraints können nur entstehen wenn die Dll andere Dll aufruft über die du dann keine Kontrolle hast.

Ergo: Ohne Code des TE raten wir nur rum...
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15806
Herkunft: BW

beantworten | zitieren | melden

Zitat von Blaster
Racing constraints können nur entstehen wenn die Dll andere Dll aufruft über die du dann keine Kontrolle hast.

Hää? Was haben denn Race Constraints mit DLLs am Hut?
private Nachricht | Beiträge des Benutzers
Blaster
myCSharp.de - Member



Dabei seit:
Beiträge: 75

beantworten | zitieren | melden

Was hat ein Zirkelbezug mit Dlls am Hut?

Und Du weist auch nicht welche Abhängigkeiten noch zwischen den Client Threads bestehen. Deshalb raten wir hier nur rum.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15806
Herkunft: BW

beantworten | zitieren | melden

Sorry, dass ich das jetzt fragen muss (auch wegen anderen aktuellen Beiträgen von Dir), aber sind Deine Beiträge hier gerade wirklich ernst oder ist das ein Trollversuch?

PS: bitte gemäß [Hinweis] Wie poste ich richtig? keine Full Quotes mehr.
private Nachricht | Beiträge des Benutzers