Subject: | Partial thread support |
UUID::Tiny doesn't work with threads. The main problem is you can't
call lock on an unshared variable, you have to declare it shared first.
By default, anything not declared shared is copied per thread (this is
far safer than the traditional threading model).
It might save a little bit of performance to not copy the Digest
objects, but its not necessary and sharing objects gets annoying,
especially XS ones.
$Last_Pid should not be shared across threads else if two threads fork
they'll clobber each other.
$Clk_Seq and $Last_Timestamp, I think, should be shared. Otherwise each
thread would have its own $Clk_Seq and increment it in parallel
presumably winding up with the same value.
With the attached patch in place, threading works... sort of. The
problem is Digest::SHA and Digest::SHA1 do not appear to be thread safe.
Creating one of their objects causes a lot of malloc warnings, but the
basic test passes. Digest::SHA::PurePerl has no such problem.
Subject: | 0001-Make-UUID-Tiny-mostly-work-with-threads.patch |
From 747483a74dba588cf3d9d0c5c88fbcab0b8886c7 Mon Sep 17 00:00:00 2001
From: Michael G. Schwern <schwern@pobox.com>
Date: Mon, 3 May 2010 18:11:35 -0700
Subject: [PATCH] Make UUID::Tiny mostly work with threads.
Digest::SHA and Digest::SHA1 have threading bugs.
---
lib/UUID/Tiny.pm | 13 ++++---------
t/threads.t | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 9 deletions(-)
create mode 100644 t/threads.t
diff --git a/lib/UUID/Tiny.pm b/lib/UUID/Tiny.pm
index 5a7623d..4954d0a 100644
--- a/lib/UUID/Tiny.pm
+++ b/lib/UUID/Tiny.pm
@@ -9,7 +9,7 @@ use MIME::Base64;
use Time::HiRes;
use POSIX;
-our $SHA1_CALCULATOR = undef;
+my $SHA1_CALCULATOR = undef;
{
# Check for availability of SHA-1 ...
@@ -22,7 +22,7 @@ our $SHA1_CALCULATOR = undef;
};
};
-our $MD5_CALCULATOR = Digest::MD5->new();
+my $MD5_CALCULATOR = Digest::MD5->new();
# ToDo:
@@ -388,8 +388,6 @@ sub _create_v3_uuid {
my $name = shift;
my $uuid = '';
- lock $MD5_CALCULATOR;
-
# Create digest in UUID ...
$MD5_CALCULATOR->reset();
$MD5_CALCULATOR->add($ns_uuid);
@@ -441,8 +439,6 @@ sub _create_v5_uuid {
;
}
- lock $SHA1_CALCULATOR;
-
$SHA1_CALCULATOR->reset();
$SHA1_CALCULATOR->add($ns_uuid);
@@ -681,7 +677,7 @@ sub equal_uuids {
# Private functions ...
#
my $Last_Pid;
-my $Clk_Seq;
+my $Clk_Seq :shared;
# There is a problem with $Clk_Seq and rand() on forking a process using
# UUID::Tiny, because the forked process would use the same basic $Clk_Seq and
@@ -690,7 +686,6 @@ my $Clk_Seq;
# time before using $Clk_Seq or rand() ...
sub _init_globals {
- lock $Last_Pid;
lock $Clk_Seq;
if (!defined $Last_Pid || $Last_Pid != $$) {
@@ -714,7 +709,7 @@ sub _init_globals {
return;
}
-my $Last_Timestamp;
+my $Last_Timestamp : shared;
sub _get_clk_seq {
my $ts = shift;
diff --git a/t/threads.t b/t/threads.t
new file mode 100644
index 0000000..139e3c5
--- /dev/null
+++ b/t/threads.t
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my $Have_Threads;
+BEGIN {
+ $Have_Threads = eval {
+ require threads;
+ require threads::shared;
+ threads::shared->import;
+ 1;
+ };
+ require Test::More;
+ Test::More->import;
+}
+
+plan skip_all => "Needs threads" unless $Have_Threads;
+
+use UUID::Tiny qw(:std);
+
+my $Num_Threads = 5;
+
+my %uuids : shared;
+$uuids{create_uuid_as_string(UUID_V4)}++;
+
+for(1..$Num_Threads) {
+ threads->create(sub {
+ $uuids{create_uuid_as_string(UUID_V4)}++;
+ });
+}
+
+note "All threads started";
+$_->join for threads->list;
+note "All threads joined";
+
+is keys %uuids, $Num_Threads + 1, "All v4 uuids should be unique per thread";
+
+done_testing;
--
1.7.0.3