Skip to content

Adds counting semaphores #206

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

Merged
merged 9 commits into from
Dec 15, 2014

Conversation

adamruzicka
Copy link
Contributor

An attempt on implementation of counting semaphores requested in Issue #162 , both mutex and java implementations should be working

Two questions about reduce_permits:
first, in Java it is a protected method used (according to the docs[1]) in subclasses that use semaphores to track resources that become unavailable. Is this method needed?

second, does it make sense to raise an error if doing the reduce would bring available permits below zero? Another approach would be to reduce available permits to zero if anyone attempted to do this

[1] https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html#reducePermits(int)

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.13%) when pulling 8fa3f05 on adamruzicka:counting-semaphores into 6af1316 on ruby-concurrency:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.08%) when pulling 3e9116b on adamruzicka:counting-semaphores into 6af1316 on ruby-concurrency:master.

@jdantonio
Copy link
Member

@adamruzicka Thank you very much for working on this. Your code looks fantastic! I really appreciate you working on both the Ruby and Java versions and also writing great yarddoc. I will try to look at this more deeply and answer your questions as soon as possible. Our company holiday party is tomorrow night so if I'm not able to get you feedback tonight it probably won't be until this weekend. I apologize for the possible delay.

@adamruzicka
Copy link
Contributor Author

@jdantonio Thank you. No need to hurry, enjoy the party. I'm sorry for the Java tests failing, I'll try to resolve it as soon as possible.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.08%) when pulling 0f59e8f on adamruzicka:counting-semaphores into 6af1316 on ruby-concurrency:master.

# @return [Integer]
def drain_permits
@mutex.synchronize do
@free.tap { |_| @free = 0 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this line be simply @free = 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to make it consistent with the Java api and it should return the number of drained permits.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that @free = 0 will return 0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible minor optimization removing the block:

@mutex.synchronize { old, @free = @free, 0 }
return old

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pitr-ch I believe that in your example old needs to be declared outside the block else its scope will only be within the block:

def drain_permits
   old = 0
   @mutex.synchronize { old, @free = @free, 0 }
   old
end

@adamruzicka If you have a free moment over the next few days, can you please test these variations? I know it may seem somewhat pedantic, but we've learned that these minor variations can often hide troubling concurrency bugs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jdantonio yep, you are right, I've overlooked it. Functional alternative:

def drain_permits
   old, _ = @mutex.synchronize { old, @free = @free, 0 }
   old
end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some testing of the variations[1], the tap one seems to perform slightly better than the others. Is there anything wrong with using tap?

[1] http://pastie.org/9779681
edit: I never did performance testing before so please let me know if this doesn't actually prove anything

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamruzicka So long as everything happens within the mutex, tap is fine. I'm surprised that tap is the fastest variation, but the numbers don't lie. Thank you for humoring us and looking into this!

Timing with a simple clock the way you did is perfectly fine, but you may want to take a look at Ruby's Benchmark class. It provide's more information. You can see how it's used in the couple of benchmark scripts in the examples folder.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some more testing, see https://gist.github.com/pitr-ch/43fd7c52f01e0cc56cea The tap is slower in the end but only a little. Big surprise for me, thanks @adamruzicka for bringing it up.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.03%) when pulling 8a1f8c6 on adamruzicka:counting-semaphores into 6af1316 on ruby-concurrency:master.

jdantonio added a commit that referenced this pull request Dec 15, 2014
@jdantonio jdantonio merged commit 821d47e into ruby-concurrency:master Dec 15, 2014
@jdantonio jdantonio removed the unknown label Dec 15, 2014
@adamruzicka
Copy link
Contributor Author

@jdantonio Thanks!

@jdantonio
Copy link
Member

Thank you! We appreciate the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants