[C#] Executie verloopt niet sequentieel met timers in thread

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online
..

[ Voor 102% gewijzigd door ? ? op 25-01-2013 09:41 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Waarom zou je 3 timers gebruiken in the first place? Je kunt met 1 timer toch ook die acties alle 3 starten :?

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online
..

[ Voor 98% gewijzigd door ? ? op 25-01-2013 09:41 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Als de volgorde van belang is lijkt het me handiger om 1 timer te gebruiken die (gezien je gegeven tijden) elke 5 minuten kijkt welke acties uitgevoerd zouden moeten worden. Het los starten van verschillende timers geeft geen enkele garantie over de volgorde waarin ze uitgevoerd worden.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Fastman schreef op woensdag 10 juni 2009 @ 14:58:
Nee de intervallen zijn verschillend (send:15m, popcheck:10m, timeout:30m ofzo), my bad. slechts om te testen staan ze allemaal op 1 minuut.
Dan start je één timer met een interval op 1 minuut (of hell, op 1 seconde voor mijn part) en check je telkens in het timer event welke acties van de drie (vier, whatever) er uitgevoerd moeten worden :?

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online
..

[ Voor 105% gewijzigd door ? ? op 25-01-2013 09:41 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Fastman schreef op woensdag 10 juni 2009 @ 15:25:
De tijden zijn variabel, het zijn slechts voorbeeldjes, vrij in te stellen. En zelf de intervallen bijhouden is extra werk, dat regelt een timer voor je? De volgorde waarin ze starten is ook van geen probleem.
Het probleem is dat de statements in verschillende timers door elkaar uitgevoerd worden. => no problemo, ware het niet dat ze beiden op eenzelfde List zitten te werken en dat mag niet.
Dus is het wel een probleem. Als het je niet lukt om de toegang tot de list concurent te krijgen dan kun je beter er maar voor zorgen dat er telkens maar 1 proces tegelijk draait. En dat is het makkelijkste wanneer je alle 3 de acties in 1 thread uitvoert.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • .Gertjan.
  • Registratie: September 2006
  • Laatst online: 17-02 21:20

.Gertjan.

Owl!

Fastman schreef op woensdag 10 juni 2009 @ 15:25:
De tijden zijn variabel, het zijn slechts voorbeeldjes, vrij in te stellen. En zelf de intervallen bijhouden is extra werk, dat regelt een timer voor je? De volgorde waarin ze starten is ook van geen probleem.
Het probleem is dat de statements in verschillende timers door elkaar uitgevoerd worden. => no problemo, ware het niet dat ze beiden op eenzelfde List zitten te werken en dat mag niet.

Een lock(mailsSent) tijdens elke foreach loop van mailsSent List werkt niet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            lock (mailsSent)
            {
                foreach (long timeSent in mailsSent)
                {
                    if (timeSent <= timestamp)
                    {
                        sendAlert(timeSent);
                        todelete.Add(timeSent);
                    }
                }

                Debug.WriteLine("Removing # items in mailsSent: " + todelete.Count.ToString());
            
                foreach (long timeSent in todelete)
                {
                    mailsSent.Remove(timeSent);
                }
            }

Nergens anders gebruik ik een foreach. Enkel in de 2 andere timers wordt iets toegevoegd aan de mailsSent.

code:
1
lock(this) { }

Werkt ook niet. :(


//1 timer en zelf controleren zal deze problemen niet geven, maar waarom zelf iets doen als er iets voor bestaat en ik zou graag weten hoe dit op te lossen.
Je moet geen lock(this) gebruiken. Zeker als het alle 3 verschillende objecten en of classes zijn. Je moet ergens een static variabele hebben dan werkt het wel.

Je moet dus ergens een object maken dat je bij alle 3 gebruikt in de lock (ze moeten namelijk het zelfde locken anders is het idee een beetje weg).

Als lock niet werkt (of je wilt meer controle) kun je ook altijd nog Monitor.Enter en Monitor.Exit gebruiken, maar ook die moeten een object hebben wat ze kunnen locken. (met Monitor.Exit kun je ook buiten een bepaalde functie de lock weer verwijderen (automatische deadlock release ofzo), maar kan wel de code complexer)

Overigens zijn timers voor zover ik weet nooit precies (net als Thread.Sleep). Er kunnen afwijkingen ontstaan als de scheduler je geen cycles geeft (of bij tegelijk afgaan gewoon een willekeurige de beurt geeft).

Vooral bij korte Thread.Sleeps zie je dat wel eens gebeuren. Dus bv 20ms, dan kan het wel eens zijn dat hij pas na 21ms wakker wordt). Het is volgens mij ook een minimum tijd dat hij gaat sleepen. Maar dat weet ik niet zeker.

[ Voor 9% gewijzigd door .Gertjan. op 10-06-2009 16:09 ]

The #1 programmer excuse for legitimately slacking off: "My code's compiling"
Firesphere: Sommige mensen verdienen gewoon een High Five. In the Face. With a chair.


Acties:
  • 0 Henk 'm!

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 18-09 15:41

mOrPhie

❤️❤️❤️❤️🤍

Afgezien van de wijze woorden van janoz:
Is het niet gewoon verstandiger om mailSent onder te brengen in een ThreadSafe singleton en de mailchecker
meer als worker in te richten. Een threadsafe singleton zou kunnen locken op een intern readonly object, in plaats van op het te beveiligen object zelf. :)

Edit:
zie http://www.yoda.arachsys.com/csharp/singleton.html

[ Voor 11% gewijzigd door mOrPhie op 10-06-2009 16:16 ]

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17:02
.Gertjan. schreef op woensdag 10 juni 2009 @ 16:07:

Vooral bij korte Thread.Sleeps zie je dat wel eens gebeuren. Dus bv 20ms, dan kan het wel eens zijn dat hij pas na 21ms wakker wordt). Het is volgens mij ook een minimum tijd dat hij gaat sleepen. Maar dat weet ik niet zeker.
In een non-realtime systeem heb je geen enkele garantie over de tijd van een sleep/timer oid. Die 20ms die 21ms worden is een vrij optimitische situatie.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • .Gertjan.
  • Registratie: September 2006
  • Laatst online: 17-02 21:20

.Gertjan.

Owl!

farlane schreef op woensdag 10 juni 2009 @ 19:54:
[...]

In een non-realtime systeem heb je geen enkele garantie over de tijd van een sleep/timer oid. Die 20ms die 21ms worden is een vrij optimitische situatie.
:) Nou was 20 ook wel vrij kort voor de sleep (en de PC niet zo snel en was tevens bezig met een hoop andere dingen, de verschillen waren inderdaad groter dan 21, maar het was slechts een voorbeeld). Maar als je exact wil timen moet inderdaad realtime gaan (beste is zelfs zonder OS ;)). Binnen Windows ben je altijd overgeleverd aan de scheduler.

Wat ik me dan wel weer afvraag, stel ik heb een timer gemaakt met een interval van 10ms. Op een gegeven moment gaat mijn PC zichzelf te zwaar belasten waardoor mijn proces bijvoorbeeld 40ms lang de scheduler niet krijgt. Hoe gaat .NET/Windows hier dan mee om? Gaat er als het systeem weer beschikbaar is na 40ms maar 1x de timer af of staan er dan inmiddels 4 timer "ticks" in de queue die tegelijk worden afgeschoten?

The #1 programmer excuse for legitimately slacking off: "My code's compiling"
Firesphere: Sommige mensen verdienen gewoon een High Five. In the Face. With a chair.


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

.Gertjan. schreef op woensdag 10 juni 2009 @ 16:07:
[...]


Je moet geen lock(this) gebruiken. Zeker als het alle 3 verschillende objecten en of classes zijn. Je moet ergens een static variabele hebben dan werkt het wel.

Je moet dus ergens een object maken dat je bij alle 3 gebruikt in de lock (ze moeten namelijk het zelfde locken anders is het idee een beetje weg).

Als lock niet werkt (of je wilt meer controle) kun je ook altijd nog Monitor.Enter en Monitor.Exit gebruiken, maar ook die moeten een object hebben wat ze kunnen locken. (met Monitor.Exit kun je ook buiten een bepaalde functie de lock weer verwijderen (automatische deadlock release ofzo), maar kan wel de code complexer)
Concurrency is erg ingewikkeld. 'lukraak' maar wat locking en monitoring toepassen zou ik niet aanraden. Zoals de code nu geschreven is (eerst een foreach en daarna al het behandelde wissen) is het niet mogelijk om meerdere processen van dezelfde lijst gebruik te laten maken. Het synchroniseren gebeurt vervolgens over de gehele actie. Door dit dan maar met locking en monitoring op te gaan lossen lijkt mij geen goed idee. Zoals ik eerder al zei is het behoorlijk ingewikkeld en voor je het weet heb je een prachtige deadlock gecreëerd, terwijl het helemaal geen voordelen heeft.

Zolang je de code niet aanpast blijft de simpelste en meest robuuste oplossing gewoon degene waarbij alle processtappen in 1 thread gebeuren. Op deze manier is het heel simpel en straigtforward om af te dwingen dat het niet tegelijk gebeurt.

Stukje psuedo code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while (isProgramRunning){
  if (tijdVoorSent < nu) {
    doeSentActie();
    tijdVoorSent = nu + sentInterval;
  }
  if (tijdVoorPopCheck < nu) {
    doePopCheckActie();
    tijdVoorPopCheck = nu + popCheckInterval;
  }
  if (tijdVoorTimeOutCheck < nu) {
    doeTimeOutCheckActie();
    tijdVoorTimeOutCheck = nu + timeOutCheckInterval;
  }
  sleep(1 minuut);
}



Wil je daarintegen perse de boel concurrent gaan doen, ditch dan die foreach en ga met een stack structuur werken. Je hoeft dan alleen maar een lock aan te vragen op het moment dat je de pop actie uitvoert. Na de pop actie geef je de lijst weer vrij en voer je je acties uit. Mocht het eventueel zo zijn dat het item niet uit de lijst gehaald mocht worden, dan zet je die weer terug (uiteraard wel even de stack locken op het moment dat je hem weer terug zet). Pas dan kun je voordeel halen uit de multithreaded aanpak. Maar nogmaals, je maakt je programma een stuk ingewikkelder en daardoor foutgevoeliger.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • .Gertjan.
  • Registratie: September 2006
  • Laatst online: 17-02 21:20

.Gertjan.

Owl!

Janoz schreef op donderdag 11 juni 2009 @ 10:13:
[...]

Concurrency is erg ingewikkeld. 'lukraak' maar wat locking en monitoring toepassen zou ik niet aanraden. Zoals de code nu geschreven is (eerst een foreach en daarna al het behandelde wissen) is het niet mogelijk om meerdere processen van dezelfde lijst gebruik te laten maken. Het synchroniseren gebeurt vervolgens over de gehele actie. Door dit dan maar met locking en monitoring op te gaan lossen lijkt mij geen goed idee. Zoals ik eerder al zei is het behoorlijk ingewikkeld en voor je het weet heb je een prachtige deadlock gecreëerd, terwijl het helemaal geen voordelen heeft.
I know. Was meer als antwoord waarom het mis ging (ik ga niemand aanraden om lukraak maar statements neer te plempen in de hoop dat het de gewenste resultaten oplevert). Concurrency is ingewikkeld en soms zo ingewikkeld dat het menselijk brein het eigenlijk niet meer kan begrijpen. Door verkeerde implementatie van concurrency kunnen heel veel dingen stuk gaan door bijvoorbeeld zoals je aangeeft deadlocks.

Je komt niet onder Locking/Monitoring uit wanneer je met meerdere threads gaat werken, maar zoals met elke krachtige techniek, misbruik wordt gestraft. Dus als TS met multithreading gaat werken zou hij er goed aan doen zich te verdiepen in de materie en ook in de mogelijke problemen die kunnen optreden zoals het bijvoorbeeld het "Dining philosophers problem".

Ik heb me verder niet in de code van TS verdiept, maar het lock(this) viel me meteen op. Dat werkt zolang je binnen de zelfde class zou blijven, maar het wordt overal afgeraden. Dus of zijn aanpak correct is weet ik niet (als jij zegt van niet geloof ik dat :)).

The #1 programmer excuse for legitimately slacking off: "My code's compiling"
Firesphere: Sommige mensen verdienen gewoon een High Five. In the Face. With a chair.

Pagina: 1