J'ai un thread qui produit des données sous la forme d'un objet simple (record). Le thread peut produire un millier d'enregistrements pour chacun qui passe avec succès un filtre et est effectivement mis en file d'attente. Une fois l'objet mis en file d'attente, il est en lecture seule.Producteur-consommateur à double file d'attente dans .NET (vidage de variable membre forçant)
J'ai un verrou, que j'accepte une fois que l'enregistrement a passé le filtre, et j'ajoute l'élément à l'arrière de la file d'attente producteur. Sur le thread consommateur, j'acquiche le verrou, confirme que la file d'attente producer_queue n'est pas vide, définit consumer_queue pour égaler producer_queue, crée une nouvelle file d'attente (vide) et la place sur producer_queue. Sans plus de verrouillage, je file consumer_queue jusqu'à ce qu'il soit vide et répète.
Tout fonctionne parfaitement sur la plupart des machines, mais sur un serveur dual-quad particulier je vois dans les itérations ~ 1/500k un objet qui n'est pas complètement initialisé quand je le lis hors de consumer_queue. La condition est si fugace que lorsque je jette l'objet après avoir détecté la condition, les champs sont corrects 90% du temps. Donc, ma question est la suivante: comment puis-je m'assurer que les écritures sur l'objet sont vidées dans la mémoire principale lorsque la file d'attente est permutée?
Edit:
Sur le fil de producteur: (producer_queue ci-dessus est m_fillingQueue, consumer_queue ci-dessus est m_drainingQueue)
private void FillRecordQueue() {
while (!m_done) {
int count;
lock (m_swapLock) {
count = m_fillingQueue.Count;
}
if (count > 5000) {
Thread.Sleep(60);
} else {
DataRecord rec = GetNextRecord();
if (rec == null) break;
lock (m_swapLock) {
m_fillingQueue.AddLast(rec);
}
}
}
}
Dans le fil du consommateur:
private DataRecord Next(bool remove) {
bool drained = false;
while (!drained) {
if (m_drainingQueue.Count > 0) {
DataRecord rec = m_drainingQueue.First.Value;
if (remove) m_drainingQueue.RemoveFirst();
if (rec.Time < FIRST_VALID_TIME) {
throw new InvalidOperationException("Detected invalid timestamp in Next(): " + rec.Time + " from record " + rec);
}
return rec;
} else {
lock (m_swapLock) {
m_drainingQueue = m_fillingQueue;
m_fillingQueue = new LinkedList<DataRecord>();
if (m_drainingQueue.Count == 0) drained = true;
}
}
}
return null;
}
Le consommateur est le taux -limité, de sorte qu'il ne peut pas devancer le consommateur.
Le comportement que je vois est que parfois le champ Heure lit comme DateTime.MinValue; au moment où je construis la chaîne pour lancer l'exception, cependant, c'est parfaitement bien.
Je ne comprends pas bien - êtes-vous en train de dire que vous utilisez la même variable pour la file d'attente de production que la file d'attente grand public? C'est la seule pièce qui se démarque de moi. Certains exemples de code peuvent aider. –
D'après votre description du verrouillage, je ne vois pas comment 'consumer_queue' peut contenir des objets incomplètement initialisés. Est-il possible pour vous d'envoyer des fragments de code pour répondre à cette question? – jerryjvl