Interlocked.Increment

  • VB.NET
  • .NET 5–6

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von exc-jdbi.

    Wenn ich mich jetzt richtig besinne, ist das doch in C# die Operation value++, wo der Wert um ein hochgezählt wird. Das brauche ich dort regelmässig. Es gibt bei mir quasi keine Methode wo ich das nicht verwende.

    Vb.Net kennt diese Operation nicht, darum hat man das System.Threading.Interlocked.Increment eingeführt. Übrigends in (.Net 7.0) kann auch op_Increment dafür verwendet werden. Gibts die in Net 6.0 noch nicht?

    Freundliche Grüsse

    exc-jdbi
    Ich interpretier einfach mal den Microsoft-Artikel:
    Eine Variable wird um 1 erhöht. Das erfolgt als ein Schritt, der auch durch parallele Vorgänge, die auf dieselbe Variable zugreifen, nicht gestört werden kann.

    Ach, da gibt's ja weiter unten auch ein Beispiel mit Erkläung:

    The following example determines how many random numbers that range from 0 to 1,000 are required to generate 1,000 random numbers with a midpoint value. To keep track of the number of midpoint values, a variable, midpointCount, is set equal to 0 and incremented each time the random number generator returns a midpoint value until it reaches 10,000. Because three threads generate the random numbers, the Increment(Int32) method is called to ensure that multiple threads don't update midpointCount concurrently.

    die etwas komische Übersetzung ins Deutsche:

    Das folgende Beispiel bestimmt, wie viele Zufallszahlen zwischen 0 und 1.000 erforderlich sind, um 1.000 Zufallszahlen mit einem Mittelwert zu generieren. Um die Anzahl der Mittelpunktwerte nachzuverfolgen, wird eine Variable , midpointCount, gleich 0 festgelegt und jedes Mal inkrementiert, wenn der Zufallszahlengenerator einen Mittelwert zurückgibt, bis er 10.000 erreicht. Da drei Threads die Zufallszahlen generieren, wird die Increment(Int32) Methode aufgerufen, um sicherzustellen, dass mehrere Threads nicht gleichzeitig aktualisiert werden midpointCount

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ich verweise mal auf einen stackoverflow-Thread diesbezüglich, ohne damit eine Wertung abgeben zu wollen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    Was ist eine atomic operation?

    Ich weiß nicht, wie gut du dich mit dem Prozessor auskennst, aber der CPU führt OP-Code, also im Grunde eine Art Assembly aus. VB wird bevor es ausgeführt wird in diesen Assembly umgewandelt. Da Assembly sehr Low-Level ist, resultiert das darin, dass aus wenigen Zeile VB-Code viel mehr Assembly Code wird. Ein einfaches value += 1 auf jede Speicheradresse gibt es da nicht. Das wir z.B. in 3 Teile aufgeteilt. 1. Lade den Wert in Register. 2. Inkrementieren den Wert. 3. Schreibe wieder zurück in Speicher.

    Ich weiß nicht, wie gut du dich im Bereich von Multithreading auf der CPU auskennst, aber bei einem Kern laufen die Programme nicht wirklich parallel. Jeder Prozess bekommt eine feste Anzahl Assembly-Operatoren, die er ausführen kann. Danach kommt ein andere an die Reihe. Das geht immer Reihum. Eventuell kannst du dir schon denken, worauf ich hinaus will. Es kann also passieren, dass du in mitten eines VB-Coes stehen bleibst und ein andere Thread kommt an die Reihe. Ja, mitten drin. Nicht davor, oder danach. Mitten drin, da dieser auf einige Assembly Operatoren aufgeteilt wird. Wenn du also mit mehreren Threads auf die gleichen Variablen zugreifen willst, dann klappt das so nicht. Eventuell lädt Thread1 den Wert aus dem Speicher - wird von Thread2 unterbrochen - der Lädt auch den Wert - erhöht diesen - schreibt ihn wieder zurück - dann geht's weiter mit Thread1 (der noch den alten Wert bereits geladen hat) - erhöht diesen - schreibt den wieder zurück und dir ist damit eine Erhöhung verloren gegangen.

    atomic operations sind genau die Lösung für das Problem. Diese können nicht unterbrochen werden. Ein Wechsel auf einen anderen Thread erfolgt eben nur danach oder davor. Nicht mitten drin.


    exc-jdbi schrieb:

    Was meines Erachten mit SyncLock in den parallelen Vorgängen auch funktionieren sollte, also auch dann, wenn
    value += 1
    verwendet wird.

    Ja Moment, warte mal. Das ist absolut korrekt, aber weißt du was SyncLock macht? Es sorgt dafür, dass über eine Stelle im Code nur 1 Thread gleichzeitig laufen kann. Wenn dieser bereits belegt ist, dann wird sozusagen ein Sleep(1) aufgerufen und danach nochmal probiert. Atomic Operations, machen das nicht, die werden einfach nicht unterbrochen. Wenn du also z.B. 10 Thread einfach nur mit SyncLock umklammerst für ein einfaches value += 1, geht deine Performance richtig in Arsch, da alle nur aufeinander Warten und nicht wirklich viel machen. Die Concurrent-Klassen von .NET sind daher extra teilweise als Lock-Free markiert und sehr stark optimiert, um zu Zeigen, dass diese nicht unnötig warten.

    Interlocked ist also schon ein etwas speziellerer Anwendungsfall, aber in diesem sehr wichtig.


    PS: Ist ein bisschen vereinfachtes Beispiel mit der CPU und das zu erklären :) .

    //Edit: Ach man, bei so langen Antworten ist es immer blöd wenn jemand inzwischen was geantwortet hat :D .

    Haudruferzappeltnoch schrieb:

    If _Cells(x, a) Then arr(a) += 1


    Das sieht mir nach einer Array aus, und kann mit SyncLock gelöst werden. Man könnte aber die Konzeption bei diesem Fall ändern, damit System.Threading.Interlocked.Increment eingesetzt werden kann.

    @Bluespide bezieht sich in seinem Beitrag speziell nur auf die Umklammerung von value += 1. Sobald jedoch Arrays/List etc. im Spiel sind, muss es anders behandelt werden.


    Edit: Vielleicht sollte ich es doch mal testen. :D. das funkst natürlich auch mit System.Threading.Interlocked.Increment.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()