J'essaie de trouver un moyen de faire un Lock Free OU non-bloquant pour faire un Ring Ringer pour consommateur simple/consommateur unique qui va écraser les données les plus anciennes dans le tampon. J'ai lu beaucoup d'algorithmes sans verrous qui fonctionnent quand vous "renvoyez faux" si le tampon est plein - c'est-à-dire, n'ajoutez pas; mais je ne trouve même pas de pseudo-code qui parle de la façon de le faire lorsque vous avez besoin d'écraser les données les plus anciennes. J'utilise GCC 4.1.2 (restriction au travail, je ne peux pas mettre à jour la version ...) et j'ai les bibliothèques Boost, et dans le passé j'ai fait mon propre type de variable Atomic < T> qui suit assez proche de la spécification upcomming (ce n'est pas parfait, mais il est thread-safe et fait ce dont j'ai besoin).C/C++ Mémoire tampon sans verrouillage (ou non bloquante) qui écrase les données les plus anciennes?
Quand j'y ai pensé, je me suis dit que l'utilisation de ces atomiques devrait vraiment régler le problème. certains psuedo code rugueux à ce que je pensais:
template< typename T , unsigned int Size>
class RingBuffer {
private:
Atomic<unsigned int> readIndex;
Atomic<unsigned int> writeIndex;
enum Capacity { size = Size };
T* buf;
unsigned int getNextIndex(unsigned int i)
{
return (i + 1) % size;
}
public:
RingBuffer() { //create array of size, set readIndex = writeIndex = 0 }
~RingBuffer() { //delete data }
void produce(const T& t)
{
if(writeIndex == getNextIndex(readIndex)) //1
{
readIndex = getNextIndex(readIndex); //2
}
buf[writeIndex] = t;
writeIndex = getNextIndex(writeIndex); //3
}
bool consume(T& t)
{
if(readIndex == writeIndex) //4
return false;
t = buf[readIndex];
readIndex = getNexIndex(readIndex); //5
return true;
}
};
Pour autant que je peux dire, il n'y a pas de situation d'impasse ici, donc nous sommes en sécurité de ce (Si ma mise en œuvre ci-dessus est mal, même sur son pseudo-code leve, la critique constructive est toujours appréciée). Cependant, la condition de course BIG que je peux trouver est:
laisse supposer que le tampon est plein. c'est-à-dire, writeIndex +1 = readIndex; (1) se produit, tout comme la consommation est appelée. et est vrai (4) est faux, donc nous passons à lire à partir du tampon (5) se produit, et le readIndex est avancé un (donc il y a, en fait, l'espace dans le tampon (2) se produit, avançant readIndex En fait, c'est un problème classique de l'écrivain qui doit modifier le lecteur, provoquant une condition de concurrence.Sans bloquer réellement la liste entière chaque fois que j'y accède, je ne peux pas penser à un moyen de empêcher que cela se produise. Qu'est-ce que je manque ??
Je ne pense pas qu'un algorithme sans verrou existe pour cela. La raison pour laquelle les modèles producteurs/consommateurs fonctionnent sans verrouillage est parce que les producteurs et les consommateurs n'ont jamais besoin de toucher les mêmes données. Mais ce que vous proposez intimement lie les deux ensemble, ce qui nécessitera une forme de verrou. –
Vous ne pouvez certainement pas bloquer: vous n'avez aucun verrou. :-D Cela dit, je pense qu'un algorithme sans verrou pour cela serait difficile au mieux. Vous avez besoin de modifier les deux indices pour qu'ils soient atomiques ensemble, donc vous auriez vraiment besoin d'une> '. Vous devez également être capable de publier et de consommer les données de l'élément de façon atomique, ce qui est impossible à faire sans verrou dans le cas général et même pour des cas spécifiques, il est impossible de modifier les deux pointeurs et les données d'un élément . Votre algorithme a de nombreuses conditions de course. –
Merci pour les commentaires les gars. Ouais, on dirait que mon intuition était bonne ... essayer de faire une version non bloquante ne fonctionnera pas très facilement. – Nik