Diskuze: Vlákna a zámky
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 11 zpráv z 11.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Vec prvni: doporucuji promennou sdilenou mezi vlakny (i kdyz jen jedno vlakno zapisuje a ostatni ctou) oznacovat vzdy jako volatile, za urcitych okolnosti by ctena promenna mohla vracet stale stejnou hodnotu, i kdyz by se v zapisovacim vlakne jeji hodnota menila.
Vypada to, ze se v hlavnim vlakne z pameti do registru nacte aktualni hodnota promenne count_b - treba je tam dejme tomu hodnota 13, v tu chvili se vlakno uspi (stav registru procesoru se ulozi), rozebehne se vlakno na pozadi, zvysi postupne v nekolika cyklech count_b treba na 20, vlakno na pozadi se uspi, zase se spusti prvni (obnovi se stav z registru, kde je ulozena stara hodnota 13), zavola se vypis do konzole, vypise se 13 a pak se zase v dalsim cyklu tveho while nacte do registru z pameti uz spravna hodnota, takze uz se pak vypisuje spravna.
Ha, tak jsem se nechal oklamat, vypada to, ze problem je stejny, ale v jinem
miste, vypada to, ze je to jen ve vypisu konzole
Vypis do konzole je ve skutecnosti spousta instrukci, takze to vetsinou vlakno prerusi temer vzdy nekde v jejim volani, takze je tam stara hodnota promenne, protoze int hodnoty se v c# obvykle predavaji hodnotou - takze se jen vytvori kopie hodnoty promenne.
Mám ještě druhou začátečnickou otázku...
Když v kódu ošetřím kritické části následovně
<code>
static object zamek = new object();
..
..
lock (zamek)
{
// inkrementace číteče
// výpis stavu čítače
}
</code>
pak počítání funguje přesně. Jen pořád nerozumím konstrukci
"lock".
Jak třída pozná, že chci uzamknout proměnné cnt_f,cnt_b,... když jako
parametr zámku uvedu obecný objekt
Chápal bych něco jako lock(this) pro celou třídu, nebo lock(a,b) pro dané
proměnné...
A tohle má být co?
private void pocitej()
{
while (true)
{
if (count_b < 100)
count_b++;
else
break;
//Thread.Sleep(10);
Console.WriteLine("Vlákno na pozadí: {0}", count_b);
}
To neumíš napsat normální cyklus?
private void pocitej()
{
while (count_b < 100)
{
count_b++;
//Thread.Sleep(10);
Console.WriteLine("Vlákno na pozadí: {0}", count_b);
}
Volatile na všechno nestačí. Lepší je používat thread-safe metody a kolekce.
Volatile na všechno nestačí, ale když zapisuje jen jedno vlákno a ostatní vlákno/vlákna jen čtou, tak obvykle není potřeba nic synchronizovat.
lock nezamyká objekty, ale části kódu.
Části kódu, které jsou pozamykané stejným zámkem nikdy nebudou probíhat najednou, (ani když ve dvou vláknech spustíš ten samý kód, tak není možné, aby ty zamčené části běžely najednou).
ad Kit:
není třeba se pohoršovat, ten kód je pouze testovací a cykly jsem postupně
zapisoval několika způsoby, když jsem ladil přepínání vláken..
ad Satik:
volatile jsem doteď ani nikdy nepoužil, v normální literatuře (basic skill)
se o ní zmiňují sotva okrajově, pokud vůbec.
"Části kódu, které jsou pozamykané stejným zámkem nikdy nebudou
probíhat najednou"
Princip zámku je mi jasný, nerozumím syntaxi. Pokud by to bylo jak říkáš,
pak by se zámek používal spíš s parametrem "jméno", nebo ne?
V CZ překladu na http://www.albahari.com/threading/ str.21 autor píše "V
příkladu nahoře chráníme obsah metody Go(), a tím pádem i obsah
proměnných val1 a val2" (totéž co u mě lock, count_f a count_b). Ta
formulace mi vůbec nedává smysl
Volatile se používá kvůli tomu, že překladač občas používá
nějaké optimalizace, které můžou ve vícevláknových aplikacích nadělat
problémy - například dejme tomu, že máš proměnnou
cekat typu bool nastavenou na true
a kód
while (cekat)
{
nejaky kod, ktery promennou cekat vubec nepouziva
}
pokud proměnná cekat není volatile a překladač tedy neví, že se její obsah někde jinde může změnit, tak se ten cyklus může zoptimalizovat na rychlejší variantu:
if (cekat)
while (true)
{
...
}
a pak by změna hodnoty proměnné cekat na false v jiném vlákně ten cyklus nezastavila.
Ten parametr u zámku - zamykací objekt se právě používá místo jména.
"V CZ překladu na http://www.albahari.com/threading/ str.21 autor píše "V příkladu nahoře chráníme obsah metody Go(), a tím pádem i obsah proměnných val1 a val2" (totéž co u mě lock, count_f a count_b)"
Zobrazeno 11 zpráv z 11.