kwg.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // package kwg -- именованный ожидатель потоков ядра.
  2. //
  3. // Не позволяет завершиться ядру, если есть хоть один работающий поток
  4. package kwg
  5. import (
  6. "context"
  7. "sync"
  8. "time"
  9. "gitp78su.ipnodns.ru/svi/kern/v4/lev0"
  10. mL1 "gitp78su.ipnodns.ru/svi/kern/v4/lev1"
  11. "gitp78su.ipnodns.ru/svi/kern/v4/lev1/comp_spec"
  12. "gitp78su.ipnodns.ru/svi/kern/v4/lev1/log_buf"
  13. "gitp78su.ipnodns.ru/svi/kern/v4/lev1/safe_bool"
  14. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kern_ent/stream_name"
  15. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kspec"
  16. )
  17. // kernelWg -- именованный ожидатель потоков ядра.
  18. type kernelWg struct {
  19. sync.RWMutex
  20. ctx context.Context
  21. dictStream map[*stream_name.AStreamName]lev0.Bool // Словарь имён потоков с признаком работы
  22. isWork lev0.ISafeBool
  23. log comp_spec.ILogBuf
  24. }
  25. var (
  26. kernWg *kernelWg // Глобальный объект
  27. block sync.Mutex
  28. )
  29. // GetKernelWg -- возвращает новый именованный ожидатель потоков ядра.
  30. func GetKernelWg(ctx context.Context) kspec.IKernelWg {
  31. block.Lock()
  32. defer block.Unlock()
  33. if kernWg != nil {
  34. kernWg.log.Debug("GetKernelWg()")
  35. return kernWg
  36. }
  37. lev0.If(ctx == nil).Hassert("GetKernelWg(): ctx==nil")
  38. paramLogBuf := &log_buf.LogBufParam{
  39. IsTerm_: safe_bool.NewSafeBool(true),
  40. Prefix_: lev0.LetTxt("kernelWg"),
  41. }
  42. sf := &kernelWg{
  43. ctx: ctx,
  44. dictStream: map[*stream_name.AStreamName]lev0.Bool{},
  45. isWork: mL1.NewSafeBool(false),
  46. log: mL1.NewLogBuf(paramLogBuf),
  47. }
  48. sf.log.Debug("GetKernelWg(): run")
  49. go sf.close()
  50. sf.isWork.Set()
  51. kernWg = sf
  52. return kernWg
  53. }
  54. // Log -- возвращает лог ожидателя потоков.
  55. func (sf *kernelWg) Log() comp_spec.ILogBuf {
  56. return sf.log
  57. }
  58. // Len -- возвращает размер списка ожидания потоков.
  59. func (sf *kernelWg) Len() lev0.Int {
  60. sf.RLock()
  61. defer sf.RUnlock()
  62. return lev0.Int(len(sf.dictStream))
  63. }
  64. // IsWork -- возвращает признак работы ядра.
  65. func (sf *kernelWg) IsWork() lev0.Bool {
  66. return sf.isWork.Get()
  67. }
  68. // List -- возвращает список имён потоков на ожидании.
  69. func (sf *kernelWg) List() []*stream_name.AStreamName {
  70. sf.RLock()
  71. defer sf.RUnlock()
  72. lst := make([]*stream_name.AStreamName, 0, len(sf.dictStream))
  73. for name := range sf.dictStream {
  74. lst = append(lst, name)
  75. }
  76. return lst
  77. }
  78. // Done -- удаляет поток из ожидания.
  79. func (sf *kernelWg) Done(name *stream_name.AStreamName) {
  80. sf.Lock()
  81. defer sf.Unlock()
  82. delete(sf.dictStream, name)
  83. sf.log.Debug("Done(): stream(%v) done", name)
  84. }
  85. // Wait -- блокирующий вызов; возвращает управление, только когда все потоки завершили работу.
  86. func (sf *kernelWg) Wait() {
  87. for {
  88. time.Sleep(time.Millisecond * 1)
  89. if !sf.isWork.Get() {
  90. break
  91. }
  92. }
  93. sf.log.Debug("Wait(): done")
  94. }
  95. // Add -- добавляет поток в ожидание.
  96. func (sf *kernelWg) Add(name *stream_name.AStreamName) {
  97. sf.Lock()
  98. defer sf.Unlock()
  99. sf.log.Debug("Add(): stream('%v') done", name)
  100. lev0.If(!sf.isWork.Get()).Hassert("Add(): stream=%v, work end", []any{name})
  101. lev0.If(name.Get() == "").Hassert("Add(): name stream is empty")
  102. _, isOk := sf.dictStream[name]
  103. lev0.If(isOk).Hassert("Add(): stream '%v' already exists", name)
  104. sf.dictStream[name] = true
  105. }
  106. // Ожидает окончания работы ожидателя групп.
  107. func (sf *kernelWg) close() {
  108. <-sf.ctx.Done()
  109. fnDone := func() bool {
  110. sf.Lock()
  111. defer sf.Unlock()
  112. return len(sf.dictStream) == 0
  113. }
  114. for {
  115. time.Sleep(time.Millisecond * 1)
  116. if fnDone() {
  117. break
  118. }
  119. }
  120. sf.Lock()
  121. defer sf.Unlock()
  122. if !sf.isWork.Get() {
  123. return
  124. }
  125. sf.isWork.Reset()
  126. sf.log.Debug(defs.TxtFix("close(): end"))
  127. }