New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing Intermittently Failing Tests #271
Conversation
@chrisseaton I've been trying to figure out why the tests for The intermittent failure seems to only occur on JRuby. More often that not the failure is a deadlock (see here). Other times the function returns the wrong value (see here). If the Is this correct? |
Yes I think that's right. If two threads raced to do the put, one of them would succeed and the other would block. That explains the deadlock. I tried to fix this, but the really tricky bit is the timeouts. I can get it correct I think up until the point where one thread has published its object and is waiting for the second. If that times out, it has to unpublished its object, but atomically. It might be best to move back to a simpler implementation using lower level primitives more directly - it might have been a mistake to try to use |
# Both threads modify the first variable
first_result = @first.modify(timeout) do |first|
# Does it currently contain the special empty value?
if first == EMPTY
# If so, modify it to contain our value
value
else
# Otherwise, modify it back to the empty state
EMPTY
end
end
# If that timed out, the whole operation timed out
return nil if first_result == MVar::TIMEOUT
# What was in @first before we modified it?
if first_result == EMPTY
# We stored our object - someone else will turn up with the second
# object at some point in the future
# Wait for the second object to appear
second_result = @second.take(timeout)
# If that timed out, the whole operation timed out
return nil if second_result == MVar::TIMEOUT
# BUT HOW DO WE CANCEL OUR RESULT BEING AVAILABLE IN @first?
# Return that second object
second_result
else
# We reset @first to be empty again - so the other value is in
# first_result and we need to tell the other thread about our value
# Tell the other thread about our object
second_result = @second.put(value, timeout)
# If that timed out, the whole operation timed out
return nil if second_result == MVar::TIMEOUT
# We already have its object
first_result
end
end |
@chrisseaton Thank you for looking into this. I just pushed a commit (308f2c5) that includes two |
The only significant changes in this PR are for |
See #263