⚲
Project
General
Profile
Sign in
Register
Home
Projects
Help
Search
:
Ruby master
All Projects
Ruby
»
Ruby master
Overview
Activity
Roadmap
Issues
Repository
Like
Download (2.18 KB)
Bug #10892
» autoload_bug.rb
Eregon (Benoit Daloze)
, 02/23/2015 12:34 PM
# Module#autoload (concurrently) blocks others threads while doing an autoload ERROR
repeated_concurrent_autoload
=
'
prev_value = COUNTER.increment_and_get
eval <<-RUBY_EVAL
module Mod#{prev_value}
sleep(0.05)
def self.foo
end
end
RUBY_EVAL
'
file_path
=
File
.
expand_path
"repeated_concurrent_autoload.rb"
File
.
write
(
file_path
,
repeated_concurrent_autoload
)
class
CyclicBarrier
def
initialize
(
count
)
@count
=
count
@state
=
0
@mutex
=
Mutex
.
new
@cond
=
ConditionVariable
.
new
end
def
await
@mutex
.
synchronize
do
@state
+=
1
if
@state
>=
@count
@state
=
0
@cond
.
broadcast
true
else
@cond
.
wait
@mutex
false
end
end
end
def
enabled?
@mutex
.
synchronize
{
@count
!=
-
1
}
end
def
disable!
@mutex
.
synchronize
do
@count
=
-
1
@cond
.
broadcast
end
end
end
class
ThreadSafeCounter
def
initialize
(
value
=
0
)
@value
=
value
@mutex
=
Mutex
.
new
end
def
get
@mutex
.
synchronize
{
@value
}
end
def
increment_and_get
@mutex
.
synchronize
do
prev_value
=
@value
@value
+=
1
prev_value
end
end
end
autoload_path
=
file_path
.
sub
(
/\.rb\Z/
,
''
)
mod_count
=
30
thread_count
=
16
mod_names
=
[]
mod_count
.
times
do
|
i
|
mod_name
=
:"Mod
#{
i
}
"
autoload
mod_name
,
autoload_path
mod_names
<<
mod_name
end
barrier
=
CyclicBarrier
.
new
thread_count
COUNTER
=
ThreadSafeCounter
.
new
threads
=
(
1
..
thread_count
).
map
do
Thread
.
new
do
mod_names
.
each
do
|
mod_name
|
break
false
unless
barrier
.
enabled?
was_last_one_in
=
barrier
.
await
# wait for all threads to finish the iteration
# clean up so we can autoload the same file again
$LOADED_FEATURES
.
delete
(
file_path
)
if
was_last_one_in
&&
$LOADED_FEATURES
.
include?
(
file_path
)
barrier
.
await
# get ready for race
begin
Object
.
const_get
(
mod_name
).
foo
rescue
NoMethodError
barrier
.
disable!
break
false
end
end
end
end
# check that no thread got a NoMethodError because of partially loaded module
p
threads
.
map
(
&
:value
)
p
threads
.
all?
(
&
:value
)
# check that the autoloaded file was evaled exactly once
p
COUNTER
.
get
p
mod_count
« Previous
1
2
Next »
(1-1/2)
Loading...