Asynchroon (II) bijv.nw. (comp.sci.) – synchroon (deel II)

 
24 oktober 2011

In een vorige post van lang geleden verbaasde ik me over het gebruik van de term ‘asynchroon’ binnen de informatiseringswereld. Maar je bent nooit te oud om te leren (ik in elk geval nog niet) en ik heb net geleerd dat een deel van het vraagstuk hem erin zit dat er meer gebeurt dan wat je ouders je vroeger verteld hebben:

Bij multithreaded applicaties heb je in Java de mogelijkheid om bij methoden het keyword synchronized of annotatie @Synchronized mee te geven, en in .Net is er het attribuut [MethodImpl(MethodImplOptions.Synchronized)]. Twee threads kunnen dan niet tegelijkertijd die methode (of een andere gesynchronizede methode uit die klasse) uitvoeren. Soortgelijk kan je explicieter en ook nauwkeuriger met lock(myobject) { ... } in C# of synchronized(myobject) { ... } in Java aangeven dat een bepaald stuk code maar met een enkele thread tegelijk toegankelijk is.

Nu is dat niet het enige dat wordt bereikt: er gebeurt ook nog iets anders, en daarbij komt het woordt ’synchroniseren’ wel in de normale betekenis in voor – namelijk ongeveer zoals in ‘twee horloges synchroniseren’.

Het geheugenmodel van Java (JLS hoofdstuk 17) en naar ik aanneem analoog ook de .Net CLR, specificeert namelijk dat een thread de door hem gebruikte variabelen mag cachen en dan met de gecachete waarden kan werken. Dit maakt het voor de compilers en VMs ook mogelijk om bepaalde optimalisaties door te voeren. De keerzijde is dat een wijziging aan een variabele daarmee dus niet direct zichtbaar is in andere threads omdat die in de thread-specifieke cache blijft hangen – en door die optimalisaties zelfs nooit zichtbaar hoeft te worden als je niet oplet.

Dat kan lastig zijn: als je bijvoorbeeld in thread A doet: while(!stopRequested) { ... }, en de variabele stopRequested wordt vanuit thread B op true gezet, dan blijft die waarde dus in de cache van thread B hangen; thread A ziet geen verschil en de lus blijft dus gewoon lekker doorlopen…

Het woord ’synchronized’ blijkt hierop van invloed te zijn: bij het binnengaan en het verlaten van een synchronized block of methode is de JVM verplicht om de thread-specifieke cache eerst te synchroniseren met het main memory. Compilers en VMs mogen ook niet tijdens optimalisatie de instructies zodanig doorelkaar gooien dat instructies binnen het synchronized gedeelte voor (of na) de instructies uit dat blok plaatsvinden en andersom.

Op deze manier wordt gegarandeerd dat de state zoals die vlak voor het synchronized gedeelte (en ook weer vlak voor het einde ervan) in de thread aanwezig is, zichtbaar kan worden binnen andere threads. Natuurlijk is er nog geen directe garantie dat dat ook gebeurt: daarvoor moeten die andere threads ook weer eerst hun thread-specifieke cache synchroniseren met het main memory, bijvoorbeeld door een eigen synchronized block aan te roepen.

Dus vandaar dat zowel de getters als de setters van die variabelen gesynchroniseerd moeten worden: de setter, zodat bij het einde van het synchronized block thread B de nieuwe waarde van stopRequested naar het main memory schrijft, en de getter zodat thread A eerst de meest recente waarde uit dat geheugen opvist voordat hij de waarde ervan bekijkt.

Dat is althans een deel van de oplossing van het vraagstuk uit mijn eerdere posting. Waarom er in .Net dan ook steeds sprake is van Async dit en Async dat, zonder dat er per se synchronized blocks in het spel zijn, moet ik nog uit zien te vinden. Dus waarschijnlijk volgt over een hele poos nog wel weer een deel III van dit onderwerp.

Als je hier nieuw bent, wil je je misschien inschrijven voor onze RSS feed.
Bedankt voor je bezoek!

Gerelateerde bijdragen

  • Er zijn geen gerelateerde bijdragen gevonden.

Werken met Jasper Stein?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development


Reacties (2)

  • Andries Nieuwenhuize schreef:

    Dag Jasper,
    wel grappig dat je dit zo stelt. Nooit over nagedacht dat sync idd inhoud dat je twee of meerdere ‘dingen’ gelijktijdig laat opgaan. Ik moest even hard nadenken om er achter te komen waarom async voor mij eerder wel logisch klonk. Ik denk dat de verwarring komt omdat de implementatie van async meerdere threads gebruikt en dat hier veel op gefocust wordt. Wiki vertelt dat async. processen geen kloksignaal nodig hebben en ik denk dat dát de positie is waar vanuit we naar dit (a)sync model moeten kijken. Normaal heb je 1 thread die zijn stack netjes afloopt en daardoor automatisch synchroon moet lopen met de CPU. Dus binnen de scope van 1 thread is dit sync en als er andere threads gebruikt worden binnen dat zelfde programma is het vanuit die ene thread gezien async omdat hij zelf niet meer bepaalt om samen gelijk op te gaan. Hij kan bijvoorbeeld wachten terwijl een broertje thread gewoon doorgaat. In de biologie is het synchroon uitkomen van eitjes dat de vogeltjes eerst uit dr eitje komen, dan pas leren vliegen enz., en asynchroon uitkomen is dan dat er al enkele vogeltjes aan het fladderen zijn terwijl anderen nog bezig zijn uit dr eitje te komen. Maar interessant dat je dit model eens goed uitzoekt. Ben benieuwd naar je volgende post over .NET. De async-uitgangen van sommige methoden (of -invoke, Endinvoke) is omdat je meerdere functies nodig hebt omdat je binnen 1 thread niet een methode half uit kan voeren en op moment x weer verder kan gaan – een soortje coroutine. Als je het interessant vindt, werp ook eens een blik op het Async. programming model van F# [1]. Die gebruikt meerdere threads uit de pool om zowél asynchroon- als parallelleverwerking (= synchroon over meerder threads!) mogelijk te maken.

    Groet,

    Andries

    1 http://www.cl.cam.ac.uk/~tp322/papers/async.pdf

    Geplaatst op 09 november 2011 om 11:49 Permalink

    • Jasper Stein schreef:

      Hej Andries,
      Interessant om te zien dat je het woord ‘asynchroon’ ook nog eens vanuit meerdere perspectieven kan bekijken waarvan er dan sommige wel en andere niet opgaan. Maar inderdaad, de focus ligt vaak op multithreaded operaties terwijl er dus meer aan de hand is en het woord vooral ook daarop lijkt te slaan. Ik zal dat artikel over F# zeker eens doorlezen als ik tijd heb, en hoewel ik nog niet direct plannen heb – hopelijk komt het inderdaad ooit nog eens tot een deel III!

      Geplaatst op 09 november 2011 om 12:10 Permalink

Plaats een reactie

Jouw emailadres wordt nooit gepubliceerd of gedeeld. Benodigde velden zijn met * gemarkeerd.