2011-10-06 4 views
3

Je suis en cours d'exécution d'une requête et traiter les lignes en utilisant simultanément retour une fonction appelée StartJob qui travaillera sur mon emploi:Bloquer l'accès simultané ThreadPool

ThreadPool.QueueUserWorkItem(StartJob, job); 

fonctionne très bien et est très rapide . Mais maintenant, on me dit que lorsque la requête retourne, certaines lignes peuvent avoir la même valeur pour job.UserID et que nous ne pouvons pas exécuter la fonction StartJob simultanément pour des valeurs identiques de job.UserID. La question est: comment puis-je avoir l'exécution du bloc StartJob jusqu'à ce que toutes les autres instances de StartJob avec le même UserID soient terminées?

Je suis sûr qu'il existe un moyen d'obtenir un verrou par utilisateur, mais je ne sais pas comment le faire. Merci pour l'aide.

+0

Il n'y aura pas de choc de si vous exécutez concurrency StartJob avec la même job.UserID jusqu'à ce qu'il vise à une ressource partagée comme un fichier ou à la ligne base de données. Pourriez-vous montrer ce que vous faites dans StartJob? –

+0

Quelle version de .NET? 3.5 ou 4.0? – xanatos

+0

@invisible tout à fait raison, j'exécute plus de requêtes dans StartJob qui verrouillent les lignes détenues par UserID et nous voyons donc un timeout car ces requêtes de longue durée verrouillent ces lignes. Donc, je voudrais démarrer StartJob avec un verrou spécifique à UserID et bloquer juste là jusqu'à ce qu'il soit gratuit. – powlette

Répondre

1
HashSet<int> hs = new HashSet<int>(); // In common with all the threads 

int id = 1; // Your id 

// This is the body of your Thread. You pass it the id as you want. 
// A closure on it, or as a parameter of the thread. 

// This will begin with short spins, every time trying to add the id to the hashset. 
// SpinUntil stops when the lambda function returns true. 
SpinWait.SpinUntil(() => 
{ 
    lock (cd) 
    { 
     return hs.Add(id); 
    } 
}); 

// OR, if you know the operation is slow, or < .NET 4.0 

// This is clearer. The thread yields until it can add the id to the hashset. 
while (true) 
{ 
    lock (hs) 
    { 
     if (hs.Add(id)) 
     { 
      break; 
     } 
    } 

    Thread.Yield(); 
} 

// End of the variant 

// Remember the try/finally! It's important in case of exceptions!!! 
try 
{ 
    // Put here your code 
    // Put here your code 
    // Put here your code 
} 
finally 
{ 
    lock (hs) 
    { 
     hs.Remove(id); 
    } 
} 

Deux versions, une qui est bon pour court StartJob et ne fonctionne que sur .NET 4.0, qui fonctionne avec .NET> = 3.5.

Clairement hs est en commun entre tous les threads, et id est le job.UserID. Je vais ajouter que sous .NET 4.0, vous pouvez utiliser SpinLock au lieu de lock. C'est un peu plus rapide, mais sa syntaxe est un peu compliquée.

1

utilisation tâche de la bibliothèque parallèle

var tasks = new Dictionary<int, Task>(); 

QueueJob(Job job) 
{ 
    lock(tasks) 
     if (tasks.ContainsKey(job.UserID)) 
     { 
     var newTask = tasks[job.UserID].ContinueWith(_=>StartJob(job)); 
     tasks[job.UserID] = newTask; 
     } 
     else 
      tasks[job.UserID] = Task.Factory.StartNew(()=>StartJob(job));     
} 
+0

Pas tâche.ContinueWith, lastTask.ContinueWith – xanatos

+0

@xanatos yea l'a corrigé. Merci. –

+0

+1 Et probablement plus lisible que http://pastebin.com/Hreck9VE – xanatos