2010-02-05 2 views
13

dois-je verrouiller l'événement dans le cas suivant:devrais-je verrouiller «événement»?

événement foo;

thread A: appelle foo + = gestionnaire;

thread B: appelle foo - = gestionnaire;

devrais-je verrouiller foo?

+1

La réponse de Jon est bonne, mais avant de répondre, je repousserais pour demander pourquoi vous voulez faire la serrure en premier lieu. * Quel problème croyez-vous avoir, et pourquoi croyez-vous que le verrouillage le résout? * Je peux penser à plusieurs problèmes que vous pourriez avoir autour des événements multithread; vous utiliseriez différentes techniques de verrouillage en fonction du problème qui vous préoccupait. –

Répondre

24

Verrouiller foo est une mauvaise idée, car la valeur changera à chaque fois. Vous devez verrouiller sur une variable qui ne le fait pas changement:

private readonly object eventLock = new object(); 
private EventHandler fooHandler; 

public event EventHandler Foo 
{ 
    add 
    { 
     lock (eventLock) 
     { 
      fooHandler += value; 
     } 
    } 
    remove 
    { 
     lock (eventLock) 
     { 
      fooHandler -= value; 
     } 
    } 
} 

private void OnFoo(EventArgs e) 
{ 
    EventHandler handler; 
    lock (eventLock) 
    { 
     handler = fooHandler; 
    } 
    if (handler != null) 
    { 
     handler(this, e); 
    } 
} 

Notez que si vous utilisez un événement comme champ, comme ceci:

public event EventHandler Foo; 

alors vous serez automatiquement obtenir un " lock (this) "sur ajouter/supprimer, bien que vous deviez l'ajouter manuellement lorsque vous récupérerez le gestionnaire avant de l'appeler (en supposant que vous voulez vous assurer de lire la dernière valeur écrite). Personnellement, je ne suis pas un fan de verrouillage sur "ceci", mais cela ne vous dérange pas - et cela rend certainement le code plus simple.

+0

@Jon, j'utilise un événement de type champ, donc je n'ai pas besoin de verrouiller sur ajouter/supprimer, ai-je raison? – Benny

+0

@Jon, j'appelle le gestionnaire d'événements en utilisant l'événement directement, comme ce foo(), ne récupérant pas le gestionnaire de l'événement, devrais-je ajouter un verrou? – Benny

+1

@Benny: Si vous utilisez un événement semblable à un champ, vous n'avez * * pas * d'ajout/de suppression à verrouiller. Si vous appelez le gestionnaire d'événements directement, comment vous protégez-vous contre le fait qu'il soit nul? Notez que vous ne pouvez pas utiliser 'if (foo! = Null) {foo (...); } 'comme' foo' pourrait * devenir * nul après le test. De plus, cela ne garantit pas que vous obtiendrez la dernière valeur - c'est pourquoi j'ai le verrouillage de ma méthode 'OnFoo'. (Les modèles de mémoire peuvent faire des choses amusantes ...) –