Programovanie

Kedy použiť volatile kľúčové slovo v C #

Optimalizačné techniky používané kompilátorom JIT (just-in-time) v prostredí Common Language Runtime môžu viesť k nepredvídateľným výsledkom, keď sa váš program .Net pokúša vykonať energeticky nezávislé načítanie údajov vo viacvláknovom scenári. V tomto článku sa pozrieme na rozdiely medzi prístupom do energeticky nezávislej a energeticky nezávislej pamäte, na úlohu energeticky nezávislého kľúčového slova v jazyku C # a na to, ako by sa malo energeticky účinné kľúčové slovo používať.

Na ilustráciu konceptov uvediem niekoľko príkladov kódu v C #. Aby sme pochopili, ako funguje volatilné kľúčové slovo, najskôr musíme pochopiť, ako funguje stratégia optimalizácie kompilátora JIT v .Net.

Pochopenie optimalizácie kompilátora JIT

Je potrebné poznamenať, že kompilátor JIT v rámci optimalizačnej stratégie zmení poradie čítaní a zápisov spôsobom, ktorý nezmení význam a konečný výstup programu. To ilustruje útržok kódu uvedený nižšie.

x = 0;

x = 1;

Vyššie uvedený útržok kódu je možné zmeniť na nasledujúci - pri zachovaní pôvodnej sémantiky programu.

x = 1;

Kompilátor JIT môže tiež použiť koncept nazývaný „neustále šírenie“ na optimalizáciu nasledujúceho kódu.

x = 1;

y = x;

Vyššie uvedený úryvok kódu je možné zmeniť na nasledujúci — opäť pri zachovaní pôvodnej sémantiky programu.

x = 1;

y = 1;

Prchavý vs. energeticky nezávislý prístup k pamäti

Pamäťový model súčasných systémov je dosť komplikovaný. Máte registre procesorov, rôzne úrovne vyrovnávacích pamätí a hlavnú pamäť zdieľanú viacerými procesormi. Keď sa váš program spustí, procesor môže údaje uložiť do medzipamäte a potom k nim pristupovať z medzipamäte, keď to vyžaduje vykonávajúce vlákno. Aktualizácie a čítania týchto údajov môžu prebiehať proti verzii dát v medzipamäti, zatiaľ čo hlavná pamäť sa aktualizuje neskôr. Tento model využívania pamäte má dôsledky pre viacvláknové aplikácie.

Keď jedno vlákno interaguje s údajmi v pamäti cache a druhé vlákno sa pokúša načítať rovnaké údaje súčasne, druhé vlákno môže čítať zastaranú verziu údajov z hlavnej pamäte. Je to tak preto, lebo keď sa aktualizuje hodnota energeticky nezávislého objektu, zmena sa vykoná v pamäti cache vykonávajúceho vlákna a nie v hlavnej pamäti. Keď sa však aktualizuje hodnota volatilného objektu, vykoná sa nielen zmena v pamäti cache vykonávajúceho vlákna, ale táto vyrovnávacia pamäť sa potom vyprázdni do hlavnej pamäte. A keď sa načíta hodnota prchavého objektu, vlákno obnoví svoju vyrovnávaciu pamäť a prečíta aktualizovanú hodnotu.

Používanie volatilného kľúčového slova v C #

Kľúčové slovo volatile v C # sa používa na informovanie kompilátora JIT, že hodnota premennej by sa nikdy nemala ukladať do medzipamäte, pretože by ju mohol zmeniť operačný systém, hardvér alebo súčasne vykonávajúce vlákno. Kompilátor sa tak vyhýba použitiu akejkoľvek optimalizácie premennej, ktorá by mohla viesť ku konfliktom údajov, t. J. K rôznym vláknam pristupujúcim k rôznym hodnotám premennej.

Keď objekt alebo premennú označíte ako nestále, stane sa kandidátom na nestále čítanie a zápis. Je potrebné poznamenať, že v C # sú všetky zápisy do pamäte volatilné bez ohľadu na to, či zapisujete dáta do volatilného alebo energeticky nezávislého objektu. Nejasnosť sa však stane, keď čítate údaje. Keď čítate dáta, ktoré nie sú trvalé, vykonávajúce vlákno môže alebo nemusí vždy získať najnovšiu hodnotu. Ak je objekt nestály, vlákno vždy dostane najaktuálnejšiu hodnotu.

Premennú môžete vyhlásiť za volatilnú tak, že pred ňu uvediete znak prchavý kľúčové slovo. Ilustruje to nasledujúci úryvok kódu.

triedny program

    {

verejny volatilny int i;

static void Main (reťazec [] args)

        {

// Sem napíš svoj kód

        }

    }

Môžete použiť prchavý kľúčové slovo s akýmkoľvek typom referencie, ukazovateľa a výčtu. Volatile modifikátor môžete tiež použiť s typmi byte, short, int, char, float a bool. Je potrebné poznamenať, že lokálne premenné nemožno deklarovať ako volatilné. Keď zadáte objekt referenčného typu ako volatilný, volatilný bude iba ukazovateľ (32-bitové celé číslo, ktoré ukazuje na miesto v pamäti, kde je objekt skutočne uložený), nie hodnota inštancie. Dvojitá premenná tiež nemôže byť volatilná, pretože má 64 bitov, je väčšia ako veľkosť slova v systémoch x86. Ak potrebujete vytvoriť dvojitú premennú volatile, mali by ste ju zabaliť do triedy. Môžete to urobiť ľahko vytvorením triedy wrapper, ako je uvedené v útržku kódu nižšie.

verejná trieda VolatileDoubleDemo

{

private volatile WrappedVolatileDouble volatileData;

}

verejná trieda WrappedVolatileDouble

{

public double Data {get; sada; }

Všimnite si však obmedzenie vyššie uvedeného príkladu kódu. Aj keď by ste mali najnovšiu hodnotu volatileData referenčný ukazovateľ, nemáte zaručenú najnovšiu hodnotu Údaje nehnuteľnosť. Práca na tom je urobiť WrappedVolatileDouble typ nemenný.

Aj keď vám kľúčové slovo volatile môže pomôcť v bezpečnosti vlákien v určitých situáciách, nie je riešením pre všetky vaše problémy so súbežnosťou vlákien. Mali by ste vedieť, že označenie premennej alebo objektu ako prchavých neznamená, že nemusíte používať kľúčové slovo lock. Prchavé kľúčové slovo nenahrádza kľúčové slovo lock. Je tu len preto, aby ste sa vyhli konfliktom údajov, keď máte viac vlákien, ktoré sa pokúšajú získať prístup k rovnakým údajom.

$config[zx-auto] not found$config[zx-overlay] not found