30 votes

Les variables statiques sont-elles thread-safe? C #

Je veux créer une classe qui stocke les tables de données, cela permettra d'éviter mon application pour importer une liste de détails à chaque fois que je veux le récupérer. Donc cela devrait être fait une fois, je crois que le code suivant ne sorte, mais je ne suis pas sûr si c'est thread-safe.

Le code ci-dessous est dans la Couche de la Section de mes trois d'application de la couche, il est de retour d'une DataTable à la Couche de Présentation.

public class BusinessLayerHandler
{
    public static DataTable unitTable;
    public static DataTable currencyTable;

    public static DataTable GetUnitList()
    {
        //import lists each time the application is run
        unitTable = null;
        if (unitTable == null)
        {
            return unitTable = DatabaseHandler.GetUnitList();
        }
        else
        {
            return unitTable;
        }
    }

    public static DataTable GetCurrencyList()
    {
        //import lists each time the application is run
        currencyTable = null;
        if (currencyTable == null)
        {
            return currencyTable = DatabaseHandler.GetCurrencyList();
        }
        else
        {
            return currencyTable;
        }
    }

Toute aide est appréciée, si il ya une meilleure façon de mettre en cache une DataTable s'il vous plaît laissez-moi savoir.

Mise à jour:

Merci pour votre avis, c'est la méthode suggérée pour le faire, si j'ai bien compris:

public class BusinessLayerHandler
{
    private static DataTable unitTable;
    private static DataTable currencyTable;

    private static readonly object unitTableLock = new object();
    private static readonly object currencyTableLock = new object();

    public static DataTable GetUnitList()
    {
        //import lists each time the application is run
        //unitTable = null;

        lock (unitTableLock)
        {
            if (unitTable == null)   
            {
                return unitTable = DatabaseHandler.GetUnitList();
            }
        }
        return unitTable;
    }

    public static DataTable GetCurrencyList()
    {
        //import lists each time the application is run
        lock (currencyTableLock)
        {
            if (currencyTable == null)
            {
                return currencyTable = DatabaseHandler.GetCurrencyList();
            }
        }
        return currencyTable;
    }
}

23voto

Adam Houldsworth Points 38632

Il semble que tout ce que vous voulez faire est de charger à la fois et de garder une référence à elle. Tous vous avez besoin de protection à l'initialisation de la variable si elle est null. Null vérification, le verrouillage et le nul de vérifier à nouveau est appelé Double-Vérifier le Verrouillage et va bien travailler pour vous. Il est recommandé de fournir un blocage séparé de l'objet, de sorte que vous avez une bonne maîtrise de la granularité de serrures.

Remarque ça ne les empêche pas les gens de la mutation de la valeur à l'intérieur de l' DataTable il ne s'arrête que les gens d'essayer d'initialiser le membre statique en même temps.

private static readonly object UnitTableLock = new object();
private static DataTable unitTable;
private static bool _ready = false;

public static DataTable GetUnitList()
{
    if (!_ready)
    {
        lock (UnitTableLock)
        {
            if (!_ready)
            {
                unitTable = new DataTable; //... etc
                System.Threading.Thread.MemoryBarrier();
                _ready = true;
            }
        }
    }

    return unitTable;
}

Uniquement lire dans la suite de l' GetUnitList jamais écrire.

Modifié en référence à http://en.wikipedia.org/wiki/Double-checked_locking

5voto

Gopher Points 597

Ils ne sont pas sûrs pour les threads. Vous devriez penser à sécuriser votre thread logique par vous-même, par exemple, en utilisant l'opérateur de verrouillage.

3voto

Matteo Mosca Points 3920

Les variables statiques ne sont pas thread-safe per se. Vous devez concevoir avec du fil de sécurité à l'esprit.

Il y a un bon lien pour vous aider à démarrer: http://en.csharp-online.net/Singleton_design_pattern%3A_Thread-safe_Singleton

En dehors de cela, je vous recommandons fortement d'utiliser une approche plus moderne de l'héritage DataTable. Découvrez le Cadre de l'Entité ou NHibernate. Mise en œuvre dans votre datalayer vous permettra de masquer les détails de la base de données du reste du logiciel et de le laisser travailler à un niveau plus élevé d'abstraction (des objets POCO).

3voto

alun Points 2006

Si vous êtes sur .net 4, vous pouvez utiliser des wrappers ThreadLocal sur vos tables de données

1voto

gjvdkamp Points 3441

Je pense que vous devriez être bien. Il y a un liight chance que 2 threads de déterminer que le datatable est nulle et de lire la table, mais seulement, on en vient à affecter l' unitTable / currencyTable référence en dernier, donc le pire des cas vous être initalizing plus d'une fois. Mais une fois qu'ils sont ensemble je pense que vous auriez bien. TANT QUE TU N'ÉCRIS PAS POUR EUX. Que pourrait laisser dans un état incohérent.

Si vous voulez éviter la double init vous pouvez rassembler l'ensemble de lecture de code dans un lock déclaration. C'est comme beaucoup d'initialisation d'un singleton.

Ajoutez également une méthode qui vous permet de définir les références à la valeur null à nouveau de sorte que vous pouvez forcer un rafraîchissement.

GJ

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X