Avatar billede jonas_h Nybegynder
20. oktober 2010 - 23:38 Der er 19 kommentarer

Lock-statement

Jeg har arbejdet for længe i dag og er træt, og pludselig blevet i tvivl om min lock statement :)

        private static object _lockForStartNumber;
        public object LockForStartNumber
        {
            get
            {
                if (_lockForStartNumber == null)
                {
                    _lockForStartNumber = new object();
                }
                return _lockForStartNumber;
            }
        }

I en web app, vil en lock(LockForStartNumber)... ikke resultere i en mutual exclusion block? Altså over samtlige requests på serveren.
Avatar billede Syska Mester
20. oktober 2010 - 23:45 #1
jo, og det kan nemt testes ved at starte 100 tråde og så tælle en op ... 1000 gange i alle tråde.

Men overstående kode synes jeg ikke rigtig giver mening ... hvorfor ikke lave dit lock object hvor der skal lockes ?

eller i hvert fald spare lidt ved at gøre sådan her:
private static object _lockForStartNumber = new object();
Avatar billede bvli Praktikant
20. oktober 2010 - 23:49 #2
Du kan ikke lave en lock på en property.
Avatar billede bvli Praktikant
20. oktober 2010 - 23:57 #3
nå jo - selvfølgelig kan du det - du _bør_ ikke. Derfor de ikke lavede SyncRoot da de lavede de nye generiske lister..
Avatar billede jonas_h Nybegynder
20. oktober 2010 - 23:57 #4
buzzz: Den lock skal bruges forskellige steder. Derfor har jeg et centralt sted til den.

bvli: Compileren og en runtime brokker sig ikke... Men mener du, at det ikke vil virke i praksis selvom koden compiler?
Avatar billede jonas_h Nybegynder
20. oktober 2010 - 23:59 #5
bvil: Nogen speciel grund til, hvor man ikke burde? Hvordan ville du lave strukturen med, at én lock skal kunne låse to forskellige steder?
Avatar billede bvli Praktikant
21. oktober 2010 - 00:06 #6
Problemet er jo egentlig, at du lægger ansvaret om at beskytte en ressource ud til klienten/brugern af ressourcen i stedet for at kapsle den ind.

Jeg læste et eller andet klogt sted på det store net omkring det issue - men jeg må nok indrømme at på denne tid af natten har jeg ikke lige den store energi til at finde det frem igen.
Avatar billede Syska Mester
21. oktober 2010 - 00:18 #7
Kort sagt ... er det vel også for at undgå dead lock ... da du nu har dit lock object åben for hele verden.

mvh
Avatar billede bvli Praktikant
21. oktober 2010 - 00:19 #8
Nå ja her var den:

Brad Adams
http://blogs.msdn.com/b/brada/archive/2003/09/28/50391.aspx

Eric Gunnerson:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemcollectionsicollectionclasssyncroottopic.asp

Og et eller andet sted handler det meste om at låse på collections, og nu ved jeg ikke lige hvad det er du vil beskytte.
Avatar billede arne_v Ekspert
21. oktober 2010 - 00:27 #9
1)

Koden i spoergsmaalet duer ikke. Den er ikke thread safe.

To traade kunne lave:

T1: if (_lockForStartNumber == null)
T2:  if (_lockForStartNumber == null)
T1: _lockForStartNumber = new object();
T1:  return _lockForStartNumber;
T2: _lockForStartNumber = new object();
T2:  return _lockForStartNumber;

buzzzz'es i #1 er ikke bare kortere med ogsaa bedre thread safe
Avatar billede arne_v Ekspert
21. oktober 2010 - 00:30 #10
2)

Der er en risiko for deadlocks hvis 2 traade skal laase 2 objekter.

Men i det tilafelde vil det jo ikke vaere thread safe at laase internt i klassen som de 2 objekter tilhoerer.
Avatar billede arne_v Ekspert
21. oktober 2010 - 00:32 #11
3)

Jeg er helt enig i at SyncRoot pattern er lidt spild. Hvis kalder har brug for at lave noget 2 objekt laasning kan han lige saa godt laase paa objektet selv.
Avatar billede janus_007 Nybegynder
21. oktober 2010 - 00:54 #12
Du kunne jo bruge en Monitor, der kan du sætte timeout for at undgå dead locks.

http://msdn.microsoft.com/en-us/library/de0542zz.aspx

Men udover det så synes jeg det er dårlig stil at lade din lock styres udefra!
imho må du ikke bruge callers til at ændre din lock, den skal sættes i klassen af den metode som anvender den. Hvis du er afhængig af at flere kaldere udfører noget som kan gå galt og det er årsagen til din åbne lock, skal du arbejde med transactions.

Anyway... dit statement bør skrives som:
....
static object syncHandle = new object();

public int StartNumber
{
get{
    lock(syncHandle)
            return startNumber;
}
}

if (!Monitor.TryEnter(syncHandle, 1000)) // vent 1 sekund
        throw new someexcpetion....
            ("Could not increment..");
    try
    {
        startNumber++;
    }
    finally
    {
        Monitor.Exit(syncHandle);
}

Ja jeg formoder din klasse skal give startnummeret og lægge 1 til? Ellers må du beskrive mere præcist hvad du vil :)
Avatar billede janus_007 Nybegynder
21. oktober 2010 - 00:55 #13
hov haha.. ja sent er det...

glemte lige at smide if(!moni... ind i en slags metode som skal kaldes for plusse en til :)
Avatar billede bvli Praktikant
21. oktober 2010 - 07:25 #14
Altså - hvis spørgsmplet drejer sig om at der skal lockes for at incrementere en værdi, så bør man bruge interlocked increment.

http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx
Avatar billede janus_007 Nybegynder
21. oktober 2010 - 09:04 #15
Interlocked gælder på instansieringen af objektet vil jeg da mene, ikke så meget en incrementor. Men det er måske nok hip som hap, det kræver ihvertfald nogle forsøg ligegyldigt hvad når man arbejder med den slags :)
Avatar billede jonas_h Nybegynder
21. oktober 2010 - 09:37 #16
For lige at beskrive mit problem:

Korrekt at der skal uddeles startnumre. Startnumre er gemt i databasen (én row pr. startnummer) og har derfor en metode som opretter nogle tilmeldinger, og tildeler startnumre til disse tilmeldinger. Hver gang den metode eksekveres, må der ikke skrives til startnummer tabellen i databasen, da jeg skal være sikker på, der ikke går noget galt.

Grunden til at jeg gerne vil kunne tilgå det object der bruges til lock er, at startnumre til tilmeldinger også kan ændres andetsteds (anden metode). Dvs. der må ikke være adgang til den metode som ændrer startnumre og den metode som tildeler til at starte med samtidigt. For at dette skal blive tilfredsstillet er de to metoder vel nødt til at lave en lock statement over et "fælles" object?
Avatar billede bvli Praktikant
21. oktober 2010 - 11:31 #17
janus: Næh.. "Increments a specified variable and stores the result, as an atomic operation"

jonas: Måske du kunne prøve at refaktorere lidt. Kunne du ikke evt. lave en StartNummerManager, som håndterer al funktionalitet omkring startnumre? Da vil du kunne lock'e internt i klassen og indkapsle det hele.
Avatar billede janus_007 Nybegynder
21. oktober 2010 - 20:08 #18
bvli-> ja det er sku det der står skrevet. Ja den må da være lige i øjet så :)

og jep, jonas_h, du bør holde det hele i en klasse, det er vi fleste nok enige om her i tråden :)
Avatar billede arne_v Ekspert
20. november 2010 - 00:02 #19
jonas?
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester