You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

semaphores.go 2.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // Copyright (c) 2018 Shivaram Lingamneni
  2. // released under the MIT license
  3. package utils
  4. import (
  5. "context"
  6. "log"
  7. "runtime/debug"
  8. "time"
  9. )
  10. // Semaphore is a counting semaphore.
  11. // A semaphore of capacity 1 can be used as a trylock.
  12. type Semaphore (chan empty)
  13. // Initialize initializes a semaphore to a given capacity.
  14. func (semaphore *Semaphore) Initialize(capacity int) {
  15. *semaphore = make(chan empty, capacity)
  16. }
  17. // Acquire acquires a semaphore, blocking if necessary.
  18. func (semaphore *Semaphore) Acquire() {
  19. (*semaphore) <- empty{}
  20. }
  21. // TryAcquire tries to acquire a semaphore, returning whether the acquire was
  22. // successful. It never blocks.
  23. func (semaphore *Semaphore) TryAcquire() (acquired bool) {
  24. select {
  25. case (*semaphore) <- empty{}:
  26. return true
  27. default:
  28. return false
  29. }
  30. }
  31. // AcquireWithTimeout tries to acquire a semaphore, blocking for a maximum
  32. // of approximately `d` while waiting for it. It returns whether the acquire
  33. // was successful.
  34. func (semaphore *Semaphore) AcquireWithTimeout(timeout time.Duration) (acquired bool) {
  35. if timeout < 0 {
  36. return semaphore.TryAcquire()
  37. }
  38. timer := time.NewTimer(timeout)
  39. select {
  40. case (*semaphore) <- empty{}:
  41. acquired = true
  42. case <-timer.C:
  43. acquired = false
  44. }
  45. timer.Stop()
  46. return
  47. }
  48. // AcquireWithContext tries to acquire a semaphore, blocking at most until
  49. // the context expires. It returns whether the acquire was successful.
  50. // Note that if the context is already expired, the acquire may succeed anyway.
  51. func (semaphore *Semaphore) AcquireWithContext(ctx context.Context) (acquired bool) {
  52. select {
  53. case (*semaphore) <- empty{}:
  54. acquired = true
  55. case <-ctx.Done():
  56. acquired = false
  57. }
  58. return
  59. }
  60. // Release releases a semaphore. It never blocks. (This is not a license
  61. // to program spurious releases.)
  62. func (semaphore *Semaphore) Release() {
  63. select {
  64. case <-(*semaphore):
  65. // good
  66. default:
  67. // spurious release
  68. log.Printf("spurious semaphore release (full to capacity %d)", cap(*semaphore))
  69. debug.PrintStack()
  70. }
  71. }