Now, if the OP's question hadn't been about performance, that probably wouldn't matter; you're right that SysV IPC is rarely used, and the MySQL code is much easier to understand and maintain. But his question was in fact about performance, and in a later post dino states specifically that the performance of MySQL was not fast enough, so advising him to use it is particularly unhelpful. Also, there are certainly more modern forms of IPC, but none that have builtin support in Perl.
Here is the code I used. If you have anything faster, please post it along with benchmarks.
Update: Fixed some errors in benchmarks (there was no row in MySQL, so the UPDATE statements weren't doing anything. Added another test with mmap+atomic_add. Fixed a typo.
counter2.pl, with MySQL. Use CREATE TABLE counter (count int); to create the table, then INSERT INTO counter VALUES (0); to put a value in it.#!/usr/bin/perl use warnings; use strict; use IPC::SysV qw(IPC_CREAT ftok SEM_UNDO); use IPC::Semaphore; my $semtok = ftok($0,1); my $shmtok = ftok($0,2); my $sem = IPC::Semaphore->new($semtok, 1, 0700 | IPC_CREAT) or die "Couldn't create semaphore: $!\n"; my $shmid = shmget($shmtok,4,0700 | IPC_CREAT) or die "Couldn't create shm: $!\n"; if ($ENV{RESET}) { $sem->setval(0,0); my $buf = pack("L",0); shmwrite($shmid, $buf, 0, 4) or die "shmwrite failed: $!\n"; if (!$ARGV[0]) { exit(0); } } foreach my $i(1..$ARGV[0]||100) { my $r = add(1); if ($ENV{VERBOSE}) { print $r,"\n"; } } sub add { my($add) = @_; # Lock: wait for 0, then semaphore up $sem->op(0, 0, 0, 0, 1, 0) or die "semaphore lock failed: $!\n"; # Read counter my $buf; shmread($shmid, $buf, 0, 4) or die "shmread failed: $!\n"; my $val = unpack("L",$buf); # Increment $val += $add; # Write it back $buf = pack("L",$val); shmwrite($shmid, $buf, 0, 4) or die "shmwrite failed: $!\n"; # Now unlock; semaphore down $sem->op(0, -1, 0) or die "semaphore unlock failed: $!\n"; return $val; }
counter3.C, mmap and atomic_add in C++ (with a little work could be done in Perl/C++ hybrid with Inline::CPP)#!/usr/bin/perl use warnings; use strict; use DBI; our $dbh = DBI->connect('DBI:mysql:database=test','db_user','db_pass') or die "Couldn't connect to db\n"; our $sth = $dbh->prepare("UPDATE counter SET count = count + ?") or die "Couldn't prepare statement\n"; foreach my $i(1..$ARGV[0]||100) { my $r = add(1); } sub add { $sth->execute($_[0]) or die "Couldn't to SQL: $!\n"; }
#include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <bits/atomicity.h> using __gnu_cxx::__atomic_add; using __gnu_cxx::__exchange_and_add; using namespace std; void die(char *msg) { perror(msg); exit(0); } void add(volatile _Atomic_word *to, int amt) { __atomic_add(to, amt); } int main(int argc, char *argv[]) { if (argc < 2) { die("bad usage"); } int mmap_fd = open(argv[1], O_RDWR); if (mmap_fd < 0) die("couldn't open mmap"); void *mem = mmap(NULL, sizeof(_Atomic_word), PROT_WRITE, MAP_SHARED, + mmap_fd, 0); if (mem == NULL) die("couldn't mmap file"); volatile _Atomic_word *counter = (volatile _Atomic_word *)mem; int count = atoi(argv[2]); for(int i=0;i<count;i++) { add(counter, 1); } cout << "counter is now " << *counter << endl; }
In reply to Re^3: Multiple write locking for BerkeleyDB
by sgifford
in thread Multiple write locking for BerkeleyDB
by dino
For: | Use: | ||
& | & | ||
< | < | ||
> | > | ||
[ | [ | ||
] | ] |