The earlier posts seem to be missing the point of a ring buffer. They require no locks when they have one writer thread and one reader thread. Using push+shift produces a queue, but not specifically a ring buffer.
For example, the keyboard buffer used to be a ring buffer. The keyboard would place messages into it to be read by the system.
What the OP is missing is that ring buffers are usually implemented using ever growing indexes into an array, mod the size of the buffer. If you don't want to limit the size of the buffer, you can use a linked list instead of an array. Hashes don't figure into the equation.
my $head = 0; # Can only be modified by the lone writer thread my $tail = 0; # Can only be modified by the lone reader thread my $size = 4; # Can hold one less than $size my @buf = (undef) x $size; # Can only be called by the lone reader thread sub is_empty { return $tail == $head; } # Can only be called by the lone reader thread sub dequeue { return () if is_empty(); my $val = $buf[$tail]; $tail = ( $tail + 1 ) % @buf; return $val; } # Can only be called by the lone writer thread sub is_full { return ($head + 1) % @buf == $tail; } # Can only be called by the lone writer thread sub enqueue { my ($val) = @_; return 0 if is_full(); $buf[$head] = $val; $head = ( $head + 1 ) % @buf; return 1; }
If you have more than one writer thread or more than one reader thread, locking is necessary.
Now, if you want to have multiple buffers going, you can use an object.
package Data::RingBuffer; sub new { my ($class, $size) = @_; return bless({ head => 0, tail => 0, buf => [ (undef) x $size ], }, $class); } sub is_empty { my ($self) = @_; return $self->{tail} == $self->{head}; } sub dequeue { my ($self) = @_; my $buf = $self->{buf}; return () if $self->is_empty(); my $val = $buf->[$self->{tail}]; $self->{tail} = ( $self->{tail} + 1 ) % @$buf; return $val; } sub is_full { my ($self) = @_; my $buf = $self->{buf}; return ($self->{head} + 1) % @$buf == $self->{tail}; } sub enqueue { my ($self, $val) = @_; my $buf = $self->{buf}; return 0 if $self->is_full(); $buf->[$self->{head}] = $val; $self->{head} = ( $self->{head} + 1 ) % @$buf; return 1; }
Update: Fixed typos in code. Simplified code.
In reply to Re: Linked lists in an array of hashes
by ikegami
in thread Linked lists in an array of hashes
by biohisham
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |