Threadsafing a mixin module without using self.new or initialize.

M

Mike Bethany

[Note: parts of this message were removed to make it a legal post.]

Threadsafing a mixin module without using self.new or initialize.

Project: Eventable - https://github.com/mikbe/eventable

Background: https://github.com/mikbe/eventable/issues/4

Problem Description:
I need to threadsafe access to an instance variable, an array. To do so I've
wrapped all methods that access the array in a mutex.synchronize block. The
problem is I'm creating the mutex in each function using @eventable_mutex
||= Mutex.new which could cause collisions if two threads try to use a
method that creates the mutex simultaneously.

I've verified this could happen: https://gist.github.com/1031308

Since this is a mixin module I can't use initialize to create the mutex
instance variable and I don't want to use trapself.new because if the class
uses this method itself then the instance variable will never be created. My
aversion to using self.new to create the instance variable is this: if I
redefine a method to fix an issue it's not unreasonable for someone else to
do the same thing. If their doing exactly what I did breaks what I did then
it's a bad fix. (see https://github.com/mikbe/eventable/pull/3)

So, my current idea for a solution is to create a class level mutex for the
inheriting class that locks on the creation of the mutex, for instance:
https://gist.github.com/1031419. This seems ugly though and I'm fairly new
to Ruby so I'm wondering if I've missed, or simply don't know about,
something that would be a better solution.
 
R

Robert Klemme

Threadsafing a mixin module without using self.new or initialize.

Project: Eventable - https://github.com/mikbe/eventable

Background: https://github.com/mikbe/eventable/issues/4

Problem Description:
I need to threadsafe access to an instance variable, an array. To do so I've
wrapped all methods that access the array in a mutex.synchronize block. The
problem is I'm creating the mutex in each function using @eventable_mutex
||= Mutex.new which could cause collisions if two threads try to use a
method that creates the mutex simultaneously.

You do not want to be creating the mutex from different threads -
because then mutex creation itself is not thread safe.
I've verified this could happen: https://gist.github.com/1031308

Since this is a mixin module I can't use initialize to create the mutex
instance variable

Why not?

module Anything
def initialize(*a,&b)
super
@lock = Mutex.new
@data = []
end
end

class Other
include Anything

def initialize
super # important!
@another_var = 15
end
end
and I don't want to use trapself.new because if the class
uses this method itself then the instance variable will never be created. My
aversion to using self.new to create the instance variable is this: if I
redefine a method to fix an issue it's not unreasonable for someone else to
do the same thing. If their doing exactly what I did breaks what I did then
it's a bad fix. (see https://github.com/mikbe/eventable/pull/3)

So, my current idea for a solution is to create a class level mutex for the
inheriting class that locks on the creation of the mutex, for instance:
https://gist.github.com/1031419. This seems ugly though and I'm fairly new
to Ruby so I'm wondering if I've missed, or simply don't know about,
something that would be a better solution.

That approach does not scale well if you have lots of instances created
concurrently. If anything fails you can add a method which creates the
mutex and which is called before the instance is used by multiple
threads - as simple as that. But I'd prefer the approach with #initialize.

Kind regards

robert
 
M

Mike Bethany

[Note: parts of this message were removed to make it a legal post.]

Since this is a mixin module I can't use initialize to create the mutex
instance variable

Why not?

module Anything
def initialize(*a,&b)
super
@lock = Mutex.new
@data = []
end
end

class Other
include Anything

def initialize
super # important!
@another_var = 15
end
end
[smacks forehead] Doh! I'm still learning Ruby, didn't even think about
that. I like the initialize method MUCH better. If they forget to include
the super it'll raise an exception when they go to use it so I just need to
make sure I document and emphasize that fact really well.


That approach does not scale well if you have lots of instances created
concurrently. If anything fails you can add a method which creates the
mutex and which is called before the instance is used by multiple threads -
as simple as that. But I'd prefer the approach with #initialize.

Yeah, I thought about that and it was why I didn't really like my solution.
Limiting creation at the class level could be a major bottleneck. Plus it
just felt hackey; but not in a good way.

Kind regards

robert


Thanks for the help!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top