Je cherche donc à utiliser une simple file d'attente producteur/consommateur en C++. Je vais finir par utiliser boost pour le threading mais cet exemple n'utilise que pthreads. Je finirai par utiliser une approche beaucoup plus orientée objet, mais je pense que cela obscurcirait les détails qui m'intéressent en ce moment.Quels sont les problèmes avec cette implémentation producteur/consommateur?
Quoi qu'il en soit les problèmes particuliers que je suis inquiet au sujet sont
- Depuis ce code utilise push_back et pop_front de std :: deque - qu'il fait probablement l'allocation et désallocation des données sous-jacentes dans différents threads - je crois c'est mauvais (comportement indéfini) - quel est le moyen le plus simple d'éviter cela?
- Rien n'est marqué comme volatile. Mais les bits importants sont protégés par mutex. Ai-je besoin de marquer quoi que ce soit comme volatile et si oui quoi? - Je ne pense pas que je le fasse car je crois que le mutex contient des barrières de mémoire appropriées etc., mais je ne suis pas sûr.
Y at-il d'autres problèmes flagrants?
Quoi qu'il en soit Heres le code:
#include <pthread.h>
#include <deque>
#include <iostream>
struct Data
{
std::deque<int> * q;
pthread_mutex_t * mutex;
};
void* producer(void* arg)
{
std::deque<int> &q = *(static_cast<Data*>(arg)->q);
pthread_mutex_t * m = (static_cast<Data*>(arg)->mutex);
for(unsigned int i=0; i<100; ++i)
{
pthread_mutex_lock(m);
q.push_back(i);
std::cout<<"Producing "<<i<<std::endl;
pthread_mutex_unlock(m);
}
return NULL;
}
void* consumer(void * arg)
{
std::deque<int> &q = *(static_cast<Data*>(arg)->q);
pthread_mutex_t * m = (static_cast<Data*>(arg)->mutex);
for(unsigned int i=0; i<100; ++i)
{
pthread_mutex_lock(m);
int v = q.front();
q.pop_front();
std::cout<<"Consuming "<<v<<std::endl;
pthread_mutex_unlock(m);
}
return NULL;
}
int main()
{
Data d;
std::deque<int> q;
d.q = &q;
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
d.mutex = & mutex;
pthread_t producer_thread;
pthread_t consumer_thread;
pthread_create(&producer_thread, NULL, producer, &d);
pthread_create(&consumer_thread, NULL, consumer, &d);
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
}
EDIT:
J'ai fini par jeter cette mise en œuvre, j'utilise maintenant une version modifiée du code de here par Anthony Williams. Ma version modifiée peut être trouvée here Cette version modifiée utilise une approche basée sur une variable de condition plus sensible.
Le problème principal est que vous nous demandez d'évaluer une solution où vous allez déchirer et jeter le thread sous-jacent, puis aussi réécrire le tout à partir de zéro d'une manière «beaucoup plus OO». Je pense que cela est connu comme une évaluation prématurée :-) – paxdiablo
@paxdiablo: Ses questions spécifiques reposent sur leurs propres mérites. Mais +1 pour la terminologie humoristique ... –
@paxdiablo J'essaie juste d'éviter les réponses inutiles de la forme "use objects" ou "use boost". Je suis bien conscient que je peux rencontrer d'autres problèmes lorsque je migre mon code - mais les réponses que j'obtiens ici resteront pertinentes dans le code modifié. –