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

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